1 package sort;
2
3 import java.util.ArrayList;
4 import java.util.Random;
5
6 public class Sort
7 {
8
9 public static Random r = new Random();
10
11
12 /**
13 * 堆排序,建立小顶堆。 0-len是待调整的数组,k指向该次被调整子树的根结点
14 */
15
16 public static void adjustDown(int arr[], int len, int k)
17 {
18 // f = l;
19 int temp = arr[k];
20
21 for (int i = 2 * k + 1; i <= len; i = 2 * i + 1)
22 {
23 // 只有右孩子存在,且右孩子又是小的结点,那么才会改变探索指针i的方向。(i一直指向待调整子树的孩子结点中值较小的结点,为了小顶堆的目标)
24 if (i < len && arr[i] > arr[i + 1])
25 {
26 i++;
27 }
28 if (temp <= arr[i])
29 {
30 break;//要么break出来,要么k继续往下走
31 }
32 else
33 {
34 arr[k] = arr[i];
35 k = i;// k一直指向,下一轮循环,待调整的子树 的父结点
36 }
37 }
38 arr[k] = temp;// 待调整的k指针没动,直接break出来,没有继续向下调整
39 }
40
41 // 堆排序,先要建立初始堆(从k到0位置,反复向下调整),然后拿出堆顶(对堆的删除),从根破坏了堆性质,又从根往下调整一次即可。
42 // 对堆的插入:新结点放在堆的末端,破坏了最下面子树的堆性质,故向上调整到某一次符合堆的性质即可
43 public static void heapSort(int arr[], int len)
44 {
45 // 这个循环建立了初始堆
46 for (int i = (len - 1) / 2; i >= 0; i--)
47 {
48
49 adjustDown(arr, len, i);
50 // Sort.disArr(arr);
51 }
52 int temp = 0;
53 for (int index = len; index >= 0;)
54 {
55 temp = arr[0];
56 arr[0] = arr[index];
57 arr[index] = temp;
58 // System.out.println(arr[index] + " ");
59 // Sort.disArr(arr);
60 index--;
61 adjustDown(arr, index, 0);// 固定从整个树的根开始向下调整
62 }
63
64 }
65
66 // 对小顶堆的插入,插入需要向上调整--AdjustUp
67 public static void insertHeap(int arr[], int k)
68 {
69
70 // k为插入结点的位置
71 int index = k;
72 int temp = arr[index];// n+1指向新放入的元素
73 while ((index - 1) / 2 >= 0 && temp < arr[(index - 1) / 2])
74 {
75 arr[index] = arr[(index - 1) / 2];// 插入的元素更小,就把父节点值放到子节点中去
76 index = (index - 1) / 2;// 默认父节点值与temp交换了,一直拿temp去和父辈,父辈的父辈……去比较
77 if (index == 0)
78 break;// 不要在根兜圈圈!减1除2,在0处就不动了
79 }
80 arr[index] = temp;
81 }
82
83 // 利用向上调整,建立初始堆。
84 // 一边不断插入元素,一边自底(k)向上(0)调整一次。
85 public static void heapSort(int arr[])
86 {
87 // 用直接插入法的思维,一个个点插入堆中,利用向上调整,建立初始堆
88 for (int i = 0; i <= arr.length - 1; i++)
89 {
90 insertHeap(arr, i);
91 }
92
93 // 还是要用到向下调整,输出序列或进行排序,因为只有堆顶元素具有“最”的特性,输出堆顶元素,从顶破坏了堆的结构,自然需要向下调整。
94 int temp = 0;
95 for (int index = arr.length - 1; index >= 0;)
96 {
97 temp = arr[0];
98 arr[0] = arr[index];
99 arr[index] = temp;
100 // System.out.println(arr[index] + " ");
101 // Sort.disArr(arr);
102 index--;
103 adjustDown(arr, index, 0);
104 }
105 }
106
107 public static void selectSort(int a[])
108 {
109 int i = 0, j = 0;
110 // int restMin = 0;
111 int index = 0;
112 int temp = 0;
113 // 从第0个位置选定元素到第倒数第二个位置,最后只剩一个元素,就不用选定位置了
114 for (i = 0; i < a.length - 1; i++)
115 {
116 // restMin = a[i];//为找到最值做准备;剩下位置中的最小值
117 index = i;// 必须先初始化为当前位置,因为最值可能就是当前位置的元素嘛
118 // j指向待比较的元素
119 for (j = i + 1; j < a.length; j++)
120 {
121 // a[index]值是变化的,用index指向剩下位置中的最小值
122 if (a[j] < a[index])
123 {
124 // restMin = a[j];//restMin保存最小值
125 index = j;// 记录最值的位置,同时a[index]自然也记录了最值的大小
126 }
127 }
128 // swap 交换最小值和当前位置元素的值
129 if (index != i)
130 {
131 temp = a[i];
132 a[i] = a[index];
133 a[index] = temp;
134 }
135
136 }
137 }
138
139 // 合并段中,把mid位置的放前后和后段,会影响mid取值的计算,以及边界的控制。
140 public static void merge(int a[], int left, int mid, int right)
141 {
142 if (left >= right)
143 return;
144
145 int index1 = 0;// 游标指向合并中的一段[0 到 mid-left-1],检测指针
146 int index2 = mid - left;// 游标指向合并中的另一段[mid-left- right - left]
147 int k = left;// 指向合并后序列的位置,存放指针
148
149 // 在a中取原数据, 在b上合并,再把最终结果保存回原来的数组a;或者copy数据到b,把合并后结果直接覆盖到a上
150 int b[] = new int[right - left + 1];
151
152 for (int i = 0; i < right - left + 1; i++)
153 {
154 b[i] = a[left + i];
155 }
156
157 while (index1 <= mid - left - 1 && index2 <= right - left)
158 {
159 if (b[index1] <= b[index2])
160 {
161 a[k++] = b[index1++];
162 }
163 else
164 {
165 a[k++] = b[index2++];
166 }
167 }
168
169 while (index1 <= mid - left - 1)
170 {
171 a[k++] = b[index1++];// 没有检测完的,复制
172 }
173 while (index2 <= right - left)
174 {
175 a[k++] = b[index2++];
176 }
177 }
178
179 public static void mergeSort(int a[], int left, int right)
180 {
181 if (left >= right)
182 return;
183 int mid = (left + right) / 2 + 1;
184 mergeSort(a, left, mid - 1);
185 mergeSort(a, mid, right);
186 merge(a, left, mid, right);
187
188 }
189
190 /**
191 *
192 * 交换排序之冒泡排序,结果升序排列
193 */
194 public static void bubbleSort(int a[])
195 {
196 int i = 0, j = 0, temp = 0;
197 boolean swaped = false;
198 // i,控制趟数,n个元素排序,最多进行n-1趟
199 for (i = 0; i < a.length - 1; i++)
200 {
201 swaped = false;
202 // j指向待排序序列,每一趟将一个待排序列中的最大元素放到该序列的最后。会有j+1,所以注意边界控制
203 for (j = 0; j < a.length - i - 1; j++)
204 {
205 if (a[j] > a[j + 1])
206 {
207 temp = a[j];
208 a[j] = a[j + 1];
209 a[j + 1] = temp;
210 swaped = true;
211 }
212 }
213 if (swaped == false)
214 {
215 return;// 本趟无逆序,停止处理
216 }
217 }
218 }
219
220 /**
221 * 交换排序之快速排序
222 */
223
224
225 public static int partition(int a[], int left, int right)
226 {
227 // 基准元素的选择对于快速排序性能影响较大;index
228 int index = left + r.nextInt(right - left + 1);// 随机选基准元素,把它放到a[left]哨兵位置,然后从right开始扫描,才是正确的
229
230
231 int value = a[index];// 用value保存了当前选取的枢轴元素,就可腾空一个位置
232
233 // 一定把枢轴元素交换至最左边(放到最左就从right开始检测,最右就应该从left开始检测),使得腾空的位置从最边上向枢轴的真正位置逼近!而不是一开始就从枢轴元素的起始位置开始移动
234
235 int temp = a[left];
236 a[left] = a[index];
237 a[index] = temp;
238
239 while (left < right)
240 {
241 // 比较中带等号,针对重复元素如:4,3,4,检测指针才会移动,不然就死循环了
242
243 // 先让右侧开始检测,对于4,9;选了9当value,直接开始right--就不对
244 while (left < right && a[right] >= value)
245 {
246 right--;
247 }
248 a[left] = a[right];
249
250 while (left < right && a[left] <= value)
251 {
252 left++;
253 }
254 a[right] = a[left];
255
256 }
257 // 必然left==right了
258 a[left] = value;
259 return left;
260 }
261
262 public static void quikSort(int a[], int left, int right)
263 {
264 if (left >= right)
265 return;
266 int p = partition(a, left, right);
267 quikSort(a, left, p - 1);
268 quikSort(a, p + 1, right);
269 }
270
271 /**
272 * 直接插入排序,结果为升序
273 *
274 * @param a
275 */
276
277 //两个指针,一个指向待插入元素,一个指向已经排好序的序列
278 public static void insertSort(int a[], int left, int right)
279 {
280 int i = 0, j = 0, temp = 0;
281 // i 指向待排序的元素。实际应用时:就是传入参数left = 0,right = a.lenght-1;
282 for (i = left + 1; i <= right; i++)
283 {
284 // 如果带排序元素需要往前插入,就不断后移动元素;如果不需要,就什么不做,直接考察下一个元素
285 if (a[i] < a[i - 1])
286 {
287 temp = a[i];// temp保存了待插入的元素
288 j = i - 1;// j指向了i之前已经有序的段
289 do
290 {
291 a[j + 1] = a[j];
292 j--;
293
294 } while (j >= left && temp < a[j]);
295 a[j + 1] = temp;// 插入temp
296 }
297 }
298 }
299
300 public static void binaryInsertSort(int arr[],int left,int right)
301 {
302 int i=0,j=0,temp=0,high = 0,low=0,middle=0;
303 for(i=left+1;i<=right;i++)
304 {
305 temp = arr[i];
306 low = left;
307 high = i-1;
308 while(low<=high)
309 {
310 middle = (low+high)/2;
311 if(temp < arr[middle])
312 {
313 high = middle - 1;
314 }
315 else
316 {
317 low = middle + 1;
318 }
319 }
320 for(j=i-1;j>=low;j--)
321 {
322 arr[j+1] = arr[j];
323 }
324 arr[low] = temp;
325 }
326 }
327
328 public static void main(String []args)
329 {
330
331 }
332 }
333