-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
151 lines (135 loc) · 3.65 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* 将链表分段
* 按一个给定值,将小于它的值放左边,大于它的值放右边,等于它的值放中间
* 方法一用数组先分段,再重组链表(shardByValue_1)
* 其中,将数组分段又提供了两种方法(splitArrByPivot_1、splitArrByPivot_1)
* 这里面一定要注意临界值和特殊情况。现在就知道对数器的使用了。
* 方法二直接在原链表上操作(TODO)
*/
package main
import (
"fmt"
"robintsai/algorithm/linkedList/share"
)
func main() {
share.Debug = true
l := share.InitRandomIntLinkedList(7)
share.DebugPrint("raw list:", l)
newList := shardByValue_1(l.Head, 3)
fmt.Println(newList)
}
// 将节点放入数组
// 对数组进行排序
// 将排序的数组重组成链表
// 解释:这个返回掩盖了题目要求的分段的段的问题,但方法是按照题目要求过程做的,重点在方法上,而不是返回结果上
func shardByValue_1(head *share.Node, pivot int) *share.SigleLinkedList {
arr := make([]*share.Node, 0, 100)
cur := head
for cur != nil {
arr = append(arr, cur)
cur = cur.Next
}
share.DebugPrint("push in arr:", arr)
gteStart, gtStart := splitArrByPivot_1(arr, pivot)
share.DebugPrint("sorted arr:", arr, gteStart, gtStart)
var newHead, newCur *share.Node
for _, n := range arr {
if newHead == nil {
newHead = n
newCur = newHead
continue
}
newCur.Next = n
newCur = n
}
newCur.Next = nil
tail := newCur
newList := &share.SigleLinkedList{
Head: newHead,
Tail: tail,
}
share.DebugPrint("sorted list:", newList)
return newList
}
// 按中轴将小者放左边,大者放右边
// 第一种方法,用了两个外层的 for
// 第一次排了 < pivot 和 >= pivot
// 第二次排了 == pivot 和 > pivot
// 返回 >= pivot 的起始位置,和 > pivot 的起始位置
func splitArrByPivot_1(arr []*share.Node, pivot int) (int, int) {
// 类似快排的分段
i := 0
j := len(arr) - 1
gteStart := 0
for i < j {
for arr[i].Value.(int) < pivot && i < j {
i++
gteStart++
}
for arr[j].Value.(int) >= pivot && i < j {
j--
}
if i < j { // swap i, j
swap(arr, i, j)
}
} // 前部分已排好
share.DebugPrint("step, sorted 1st-part:", arr, gteStart)
// 排后半部分
i = gteStart
j = len(arr) - 1
gtStart := gteStart - 1
for i < j {
for arr[i].Value.(int) == pivot && i < j {
i++
gtStart++
}
for arr[j].Value.(int) > pivot && i < j {
j--
}
if i < j {
swap(arr, i, j)
}
}
share.DebugPrint("step, ordered 2nd-part:", arr, gtStart)
return gteStart, gtStart
}
func swap(arr []*share.Node, i, j int) {
temp := arr[i]
arr[i] = arr[j]
arr[j] = temp
}
// 按中轴将小者放左边,大者放右边
// 第二种方法,只进行一次循环
// 返回 >= pivot 的起始位置,和 > pivot 的起始位置
func splitArrByPivot_2(arr []*share.Node, pivot int) (int, int) {
// 类似快排的分段
i := 0
ltEnd := -1
pivotEnd := -1
gtStart := len(arr)
// i 左边全是 <= pivot 的值
// 且 < 的全在 = 的左边
// i 右边全是 > pivot 的值
for i < gtStart {
for arr[i].Value.(int) < pivot && i < gtStart { // 每一个判断上都要带 i<gtStart
swap(arr, i, ltEnd+1)
i++
ltEnd++
}
fmt.Println("i, ltend", i, ltEnd, arr)
for arr[i].Value.(int) == pivot && i < gtStart { // 因为每一个 for 都有可能更新 i 或 gtStart
i++
pivotEnd++
}
for arr[i].Value.(int) > pivot && i < gtStart { // 若不然,就需要每一步改动都对外层 continue
swap(arr, i, gtStart-1)
gtStart--
}
}
share.DebugPrint("step, sorted:", arr)
gteStart := gtStart
if ltEnd < pivotEnd {
gteStart = ltEnd + 1
}
return gteStart, gtStart
}