各种排序
来源:互联网 发布:java 7年工作经验 编辑:程序博客网 时间:2024/06/05 11:19
快速排序:
/* 快速排序 */ //直接交换,better static int partition(Integer arr[],int low,int high){ int temp,pivot = arr[high]; while(low < high){ /* 查找顺序要和基准选取方向相反; pivot = arr[high] 则必须先从low开始; 反之 pivot = arr[low], 则必须先从high开始查找 */ while(arr[low] <= pivot && low < high) low++; arr[high] = arr[low];//直接覆盖原先的元素 while(arr[high] >= pivot && low < high) high--; arr[low] = arr[high]; } // 校准,将基准移至正确位置 arr[low] = pivot; System.out.println("low="+low+";high="+high); return low; } static void quickSort(Integer []arr,int low,int high){ if(low < high){ int pivotpos = partition(arr,low,high); quickSort(arr,low,pivotpos-1); quickSort(arr,pivotpos+1,high); } }
另一种:
static int partition(Integer a[], int low, int high) { int i = low, j = high; int temp, pivot = a[i]; while (i < j) { /* * 查找顺序要和基准选取相反; pivot = arr[high] 则必须先从low开始; * 反之 pivot =arr[low],则必须先从high开始查找 */ /** * 注意: * 1,与pivot比较必须是>=,否则在a[j]或a[i]==pivot时,会造成死循环 * 2,内层循环的i<j,保证i,j不会越过对方,因此跳出最外层循环时,i==j */ while (a[j] >= pivot && i < j) j--; while (a[i] <= pivot && i < j) i++; // i,j位置元素,两边交换,此时无需判断i<=j,此条件在该循环中恒成立 int t = a[i]; a[i] = a[j]; a[j] = t; } // 校准,将基准值移至正确位置,此时i==j a[low] = a[i]; a[i] = pivot; System.out.println("i=" + i + ";j=" + j);// i j必相等 return i;// 返回基准所在位置划分位置 } static void quickSort(Integer[] a, int low, int high) { if (low < high) { int pivotpos = partition(a, low, high); quickSort(a, low, pivotpos - 1); quickSort(a, pivotpos + 1, high); } } public static void main(String[] args) { Integer a[] = { 8,1,4,9,0,3,5,2,7,6}; quickSort(a, 0, a.length - 1); Arrays.toString(a); }
第二种
low处自始至终放的是pivot没动,最后需要把i,j指向位置的元素放到low处;
解释为什么满足放到low处:
内层两个while,先从high走,再走low;最后一次while时肯定是先不满足第一个while,第二个while又是i==j不满足;不满足第一个while但是又进得了外层的while,只能说明最后i(或j)指向的元素不满足>=pivot,即元素肯定小于pivot,所以必定满足放到low处。
这也就是为什么“查找顺序要和基准选取的方向相反”
归并排序:
//将有二个有序数列a[first...mid]和a[mid...last]合并。 void mergearray(int a[], int first, int mid, int last, int temp[]) { int i = first, j = mid + 1; int m = mid, n = last; int k = 0; while (i <= m && j <= n) { if (a[i] <= a[j]) temp[k++] = a[i++]; else temp[k++] = a[j++]; } while (i <= m) temp[k++] = a[i++]; while (j <= n) temp[k++] = a[j++]; for (i = 0; i < k; i++) a[first + i] = temp[i]; } void mergesort(int a[], int first, int last, int temp[]) { if (first < last) { int mid = (first + last) / 2; mergesort(a, first, mid, temp); //左边有序 mergesort(a, mid + 1, last, temp); //右边有序 mergearray(a, first, mid, last, temp); //再将二个有序数列合并 } } bool MergeSort(int a[], int n) { int *p = new int[n]; if (p == NULL) return false; mergesort(a, 0, n - 1, p); delete[] p; return true; }
归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。
https://visualgo.net/sorting 排序可视化
堆排序
计算堆化时间复杂度时,将父节点与子节点的比较简易化,看本质(其实就是从上到下的单支链表!因为选择堆化结点时,是先从n/2处向前遍历。从上到下比较时,调整的必是或左或右的一颗子树。其实无论是否下面的一堆化,向下调整时,每次选择必走的是单支的啊。。。),其实是该节点的深度(树高H-本层高度h)
http://blog.csdn.net/yuzhihui_no1/article/details/44258297
该博客代码,时间复杂度 均解释十分详细
阅读全文
0 0