常见排序算法的亲手实现(代码与注释)

  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         

 

posted @ 2014-09-17 21:21  jht_newbie  阅读(315)  评论(0编辑  收藏  举报