常见排序算法思路和简单代码实现
算法名称 | 算法思路 |
直接插入排序 | 每次将一个待排序的数据,插入到前面已经排好序的序列之中,直到全部数据插入完成。 |
二分法插入排序 | 首先取出原有序中间数与新插的数比较,然后插入新数大小包含于其中的一半数组,再次取该数组中间数,如此重复下去,直至最后得到数组个数为一,将最后得到的数之后的数后移,然后将新插入的数放在该索引处。 |
希尔排序 | 先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。由于希尔排序是对相隔若干距离的数据进行直接插入排序,因此可以形象的称希尔排序为“跳着插” |
简单选择排序 | 数组分成有序区和无序区,初始时整个数组都是无序区,然后每次从无序区选一个最小的元素直接放到有序区的最后,直到整个数组变有序区。 |
堆排序 |
堆排序的难点就在于堆的的插入和删除。 堆的插入就是——每次插入都是将新数据放在数组最后,而从这个新数据的父结点到根结点必定是一个有序的数列,因此只要将这个新数据插入到这个有序数列中即可。 堆的删除就是——堆的删除就是将最后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最小的,如果父结点比这个最小的子结点还小说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点开始将一个数据在有序数列中进行“下沉”。 因此,堆的插入和删除非常类似直接插入排序,只不是在二叉树上进行插入过程。所以可以将堆排序形容为“树上插” |
冒泡排序 |
通过交换使相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就“沉”到最后面了。重复N次即可以使数组有序。 冒泡排序改进1:在某次遍历中如果没有数据交换,说明整个数组已经有序。因此通过设置标志位来记录此次遍历有无数据交换就可以判断是否要继续循环。 冒泡排序改进2:记录某次遍历时最后发生数据交换的位置,这个位置之后的数据显然已经有序了。因此通过记录最后发生数据交换的位置就可以确定下次循环的范围了。 |
快速排序 | “挖坑填数+分治法”,首先令i =L; j = R; 将a[i]挖出形成第一个坑,称a[i]为基准数。然后j--由后向前找比基准数小的数,找到后挖出此数填入前一个坑a[i]中,再i++由前向后找比基准数大的数,找到后也挖出此数填到前一个坑a[j]中。重复进行这种“挖坑填数”直到i==j。再将基准数填入a[i]中,这样i之前的数都比基准数小,i之后的数都比基准数大。因此将数组分成二部分再分别重复上述步骤就完成了排序。 |
归并排序 | 当一个数组左边有序,右边也有序,那合并这两个有序数组就完成了排序。如何让左右两边有序了?用递归!这样递归下去,合并上来就是归并排序。 |
基数排序 | 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列 |
public class MyClass { public static void main(String[] args){ System.out.println("hello"); int[] a = {62,14,59,88,16,33,24,97}; System.out.print("before"); printArray(a); radixSort(a); System.out.print("after"); printArray(a); } //插入排序 public static void insertSort(int[] a) { //将a[]按升序排列 int N = a.length; //数组长度 for (int i = 1; i < N; i++) { //将a[i]插入到a[i-1] a[i-2] a[i-3]...之中 for (int j = i; (j>0)&&(a[j]<a[j-1]); j--) { //a[j]与a[j-1]交换 exch(a, j, j-1); } System.out.print("-----"+i+"-----"); printArray(a); } } //二分法插入排序 public static void binaryInsertSort(int[] array) { for (int i = 1; i < array.length; i++) { int temp = array[i]; int right = i - 1; int left = 0; int mid; // 定位 while (left <= right) { mid = (left + right) / 2; if (array[mid] > temp) { right = mid - 1; } else if (array[mid] < temp) { left = mid + 1; } } // 移动数组 for (int j = i; j > left; j--) { array[j] = array[j - 1]; } // 在找到的位置插入 array[left] = temp; System.out.print("-----"+i+"-----"); printArray(array); } } //希尔排序 public static void shellSort(int[] a){ //将a[]按升序排列 int N = a.length; //数组长度 int h = 1; while (h < N/3){ h = 3*h + 1; //1,4,13,40, } while(h >= 1){ //将数组变为h有序 for (int i = h; i <N; i++) { //将a[i]插入到a[i-h],a[i-2*h],a[i-3*h]...之中 for (int j=i; (j>=h)&&(a[j]<a[j-h]); j-=h) { //a[j]与a[j-h]交换 exch(a, j, j-h); } System.out.print("-----"+i+"-----"); printArray(a); } h = h/3; System.out.print("-----"+h+"-----"); printArray(a); } } //选择排序 public static void selectSort(int[] a) { //将a[]按升序排列 int N = a.length; //数组长度 for (int i = 0; i < N; i++) { //将a[i]与a[i+1..N]中最小的元素交换 //找出最小元素索引 int min = i; for (int j = i+1; j < N; j++) { if (a[j] < a[min]){ min = j; } } //a[i]与a[min]交换 exch(a, i, min); System.out.print("-----"+i+"-----"); printArray(a); } } //堆排序 public static void heapSort(int[] a){ int N = a.length; //数组长度 for(int i=0;i<N-1;i++){ //建堆 buildMaxHeap(a,N-1-i); //交换堆顶和最后一个元素 exch(a,0,N-1-i); System.out.print("-----"+i+"-----"); printArray(a); } } //对data数组从0到lastIndex建大顶堆 public static void buildMaxHeap(int[] data, int lastIndex){ //从lastIndex处节点(最后一个节点)的父节点开始 for(int i=(lastIndex-1)/2;i>=0;i--){ //k保存正在判断的节点 int k=i; //如果当前k节点的子节点存在 while(k*2+1<=lastIndex){ //k节点的左子节点的索引 int biggerIndex=2*k+1; //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在 if(biggerIndex<lastIndex){ //若果右子节点的值较大 if(data[biggerIndex]<data[biggerIndex+1]){ //biggerIndex总是记录较大子节点的索引 biggerIndex++; } } //如果k节点的值小于其较大的子节点的值 if(data[k]<data[biggerIndex]){ //交换他们 exch(data,k,biggerIndex); //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值 k=biggerIndex; }else{ break; } } } } //冒泡排序 public static void bubbleSort(int[] a){ //将a[]按升序排列 int N = a.length; //数组长度 for (int i = 0; i < N - 1; i++) { for (int j = i + 1; j < N; j++) { if (a[i] > a[j]){ //前面比后面数大则交换 exch(a, i, j); } } } } //快速排序 public static void quickSort(int[] a, int low, int high) { if(low < high) { int middle = getMiddle(a,low,high); //将numbers数组进行一分为二 System.out.print("-----"+middle+"-----"); printArray(a); quickSort(a, low, middle-1); //对低字段表进行递归排序 quickSort(a, middle+1, high); //对高字段表进行递归排序 } } /** * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置 * * @param numbers 带查找数组 * @param low 开始位置 * @param high 结束位置 * @return 中轴所在位置 */ public static int getMiddle(int[] numbers, int low, int high) { int temp = numbers[low]; //数组的第一个作为中轴 while (low < high) { while (low < high && numbers[high] > temp) { high--; } numbers[low] = numbers[high];//比中轴小的记录移到低端 while (low < high && numbers[low] < temp) { low++; } numbers[high] = numbers[low]; //比中轴大的记录移到高端 } numbers[low] = temp; //中轴记录到尾 return low; // 返回中轴的位置 } //归并排序 public static void mergeSort(int[] a, int low, int high){ int mid = (low + high) / 2; if (low < high) { // 左边 mergeSort(a, low, mid); // 右边 mergeSort(a, mid + 1, high); // 左右归并 merge(a, low, mid, high); } } /** * 将数组中low到high位置的数进行排序 * @param nums 待排序数组 * @param low 待排的开始位置 * @param mid 待排中间位置 * @param high 待排结束位置 */ public static void merge(int[] nums, int low, int mid, int high) { int[] temp = new int[high - low + 1]; int i = low;// 左指针 int j = mid + 1;// 右指针 int k = 0; // 把较小的数先移到新数组中 while (i <= mid && j <= high) { if (nums[i] < nums[j]) { temp[k++] = nums[i++]; } else { temp[k++] = nums[j++]; } } // 把左边剩余的数移入数组 while (i <= mid) { temp[k++] = nums[i++]; } // 把右边边剩余的数移入数组 while (j <= high) { temp[k++] = nums[j++]; } // 把新数组中的数覆盖nums数组 for (int k2 = 0; k2 < temp.length; k2++) { nums[k2 + low] = temp[k2]; } } //基数排序 public static void radixSort(int[] a) { int BASE = 10; // 整数基数 int len = a.length; int[] buffer = new int[len]; int maxValue = a[0], exp = 1; // 找出a数组中最大的数 for (int i = 1; i < len; i++) { if (a[i] > maxValue) { maxValue = a[i]; } } while (maxValue / exp > 0) { int[] bucket = new int[BASE]; //{0 0 0 0 0 0 0 0 0 0} for (int i = 0; i < bucket.length; i++) { bucket[i] = 0; } printArray(bucket); //从数的低位开始进行桶排序 {0 0 1 1 2 0 1 1 1 1} for (int i = 0; i < len; i++) { bucket[(a[i] / exp) % BASE]++; } printArray(bucket); // 按照当前位给a排序,确定各个数对应的大概位置buket[(a[i] / exp) % BASE]的值 // 即为新位置的下标 for (int i = 1; i < BASE; i++) { bucket[i] += bucket[i - 1]; } // 按当前位进行排序存入到新数组 for (int i = len - 1; i >= 0; i--) { int index = (a[i] / exp) % BASE; buffer[--bucket[(a[i] / exp) % BASE]] = a[i]; } for (int i = 0; i < len; i++) { a[i] = buffer[i]; } exp *= BASE; } } //桶排序 适用于固定范围大小内数据的排序 public static void bucketSort(int[] a, int BUCKETSIZE) { int bucket[] = new int[BUCKETSIZE]; //长度120位的数组 printArray(bucket); //对应的位有值时加1 for (int i = 0; i < a.length; ++i) { if (i <= BUCKETSIZE && i >= 0) { bucket[a[i]]++; } } printArray(bucket); //把相关的值重新赋值回数组 [0..14..16..] int index = 0; for (int i = 0; i < bucket.length; i++) { while (bucket[i] > 0) { a[index++] = i; bucket[i]--; } } } //交换两个数组元素 public static void exch(int[] a, int i, int j){ int t = a[i]; a[i] = a[j]; a[j] = t; } //打印数组元素 public static void printArray(int[] a){ for (int i = 0; i < a.length; i++) { System.out.print(" "+a[i]); } System.out.print("\n"); }
//不使用中间变量交换两个数组元素
public static void exchNotemp(int[] a, int i, int j){
a[i] = a[i] + a[j];
a[j] = a[i] - a[j];
a[i] = a[i] - a[j];
}
}
补充资料
图解排序
http://www.cnblogs.com/chengxiao/p/6194356.html