标签:
排序相关概念
排序:对一序列对象根据某个关键字进行排序;
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
内排序:所有排序操作都在内存中完成;
外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
排序耗时的操作:比较、移动;
排序分类:
(1)交换类:冒泡排序、快速排序;此类的特点是通过不断的比较和交换进行排序;
(2)插入类:简单插入排序、希尔排序;此类的特点是通过插入的手段进行排序;
(3)选择类:简单选择排序、堆排序;此类的特点是看准了再移动;
(4)归并类:归并排序;此类的特点是先分割后合并;
历史进程:一开始排序算法的复杂度都在O(n^2),希尔排序的出现打破了这个僵局;
以下视频是Sapientia University创作的,用跳舞的形式演示排序步骤,这些视频就可以当作复习排序的资料~
冒泡排序视频:http://v.youku.com/v_show/id_XMzMyOTAyMzQ0.html
选择排序视频:http://v.youku.com/v_show/id_XMzMyODk5MDI0.html
插入排序视频:http://v.youku.com/v_show/id_XMzMyODk3NjI4.html
希尔排序视频:http://v.youku.com/v_show/id_XMzMyODk5MzI4.html
归并排序视频:http://v.youku.com/v_show/id_XMzMyODk5Njg4.html
快速排序视频:http://v.youku.com/v_show/id_XMzMyODk4NTQ4.html
上面介绍的排序算法都是基于排序的,还有一类算法不是基于比较的排序算法,如计数排序、基数排序;
排序实现代码
public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}/**最简单的排序。<br>缺点是每次找最小值都是单纯的找,而没有为下一次寻找做出铺垫;*/public static int[] simple_sort(int[] arr) {for (int i = 0; i < arr.length; i++) {for (int j = i + 1; j < arr.length; j++) {if (arr[i] > arr[j]) {swap(arr, i, j);}}}return arr;}/**标准冒泡排序。思想就是两两相邻比较并交换*/public static int[] bubble_sort2(int[] arr) {for (int i = 0; i < arr.length; i++) {for (int j = arr.length - 1; j > i; j--) {if (arr[j] < arr[j - 1]) {swap(arr, j, j - 1);}}}return arr;}/**改进冒泡排序<br>改进在于如果出现一个序列,此序列基本是排好序的,如果是标准的冒泡排序,则还是需要进行不断的比较;<br>最好:n-1次比较不移动,时间复杂度为O(n),不占用辅助空间 。<br>最坏:n(n-1)/2次比较和移动,O(n^2),占用交换的临时空间,大小为1*/public static int[] bubble_sort3(int[] arr) {boolean isChanged = true;//如果一次循环中没有交换过元素,则说明已经排好序;for (int i = 0; i < arr.length && isChanged; i++) {isChanged = false;for (int j = i + 1; j < arr.length; j++) {if (arr[i] > arr[j]) {swap(arr, i, j);isChanged = true;}}}return arr;}/**简单选择排序。好于冒泡排序 <br>每次循环找到最小值,并交换,因此交换次数始终为n-1次。<br>相对于最简单的排序,对于很多不必要的交换做了改进<br>最差:n(n-1)/2次比较,n-1次交换,时间复杂度为O(n^2) 。<br>最好:n(n-1)/2次比较,不交换,时间复杂度为O(n^2)*/public static int[] selection_sort(int[] arr) {for (int i = 0; i < arr.length - 1; i++) {int min = i;for (int j = i + 1; j < arr.length; j++) {if (arr[min] > arr[j]) {min = j;}}if (min != i) swap(arr, min, i);}return arr;}/**简单插入排序。<br>比选择排序和冒泡排序好。<br>对于记录较少或基本有序时很有效<br>思想:给序列设定一个分界线,每次循环将分界线右边尚未排序的一个元素插入左侧已排序的数组中,并将分界线向右移一位<br>最好:n-1次比较,0次移动,时间复杂度为O(n) 。<br>最差:(n+2)(n-1)/2次比较,(n+4)(n-1)/2次移动,时间复杂度为 O(n^2) */public static int[] insertion_sort(int[] arr) {int j;for (int i = 1; i < arr.length; i++) {if (arr[i] < arr[i - 1]) {int tmp = arr[i];for (j = i - 1; j >= 0 && arr[j] > tmp; j--) {arr[j + 1] = arr[j];}arr[j + 1] = tmp;}}return arr;}/**希尔排序。<br>第一个突破O(n^2)的排序算法;是简单插入排序的改进版<br>思想:通过将序列进行分组排序使得每组容量变小,再进行分组排序,然后进行一次简单插入排序即可<br>时间复杂度为:O(n^(3/2)) 。<br>不稳定排序算法 */public static int[] shell_sort(int[] arr) {int j;int increment = arr.length;//如果increment=3,则i%3相等的索引为一组,比如索引1,1+3,1+3*2do {increment = increment / 3 + 1;//一般增量公式为:increment = increment/3+1for (int i = increment; i < arr.length; i++) { //i=increment 因为插入排序默认每组的第一个记录都是已排序的if (arr[i] < arr[i - increment]) {int tmp = arr[i];for (j = i - increment; j >= 0 && arr[j] > tmp; j -= increment) {arr[j + increment] = arr[j];}arr[j + increment] = tmp;}}} while (increment > 1);return arr;}/**堆排序。<br>是简单选择排序的改进版<br>思想:构建一棵完全二叉树,首先构建大根堆,然后每次都把根节点即最大值移除,并用编号最后的节点替代,这时数组长度减1,然后重新构建大根堆,以此类推;<br>时间复杂度为O(nlogn)。辅助空间为1。<br>不稳定排序算法<br>不适合排序个数较少的序列,因为初始构建堆需要时间*/public static int[] heap_sort(int[] arr) {int tmp[] = new int[arr.length + 1];tmp[0] = -1;for (int i = 0; i < arr.length; i++) {tmp[i + 1] = arr[i];}// 构建大根堆:O(n)for (int i = arr.length / 2; i >= 1; i--) {makeMaxRootHeap(tmp, i, arr.length);}// 重建:O(nlogn)for (int i = arr.length; i > 1; i--) {swap(tmp, 1, i);makeMaxRootHeap(tmp, 1, i - 1);}for (int i = 1; i < tmp.length; i++) {arr[i - 1] = tmp[i];}return arr;}private static void makeMaxRootHeap(int[] arr, int low, int high) {int tmp = arr[low];int j;for (j = 2 * low; j <= high; j *= 2) {if (j < high && arr[j] < arr[j + 1]) {j++;}if (tmp >= arr[j]) {break;}arr[low] = arr[j];low = j;}arr[low] = tmp;}/**归并排序。<br>思想:利用递归进行分割和合并,分割直到长度为1为止,并在合并前保证两序列原本各自有序,合并后也有序<br>时间复杂度O(nlogn) 。空间复杂度:O(n+logn) 。<br>稳定排序;*/public static int[] merge_sort(int[] arr) {Msort(arr, arr, 0, arr.length - 1);return arr;}private static void Msort(int[] sr, int[] tr, int s, int t) {int tr2[] = new int[sr.length];int m;if (s == t) {tr[s] = sr[s];} else {m = (s + t) / 2;Msort(sr, tr2, s, m);Msort(sr, tr2, m + 1, t);Merge(tr2, tr, s, m, t);}}private static void Merge(int[] tr2, int[] tr, int i, int m, int t) {int j, k;for (j = i, k = m + 1; i <= m && k <= t; j++) {if (tr2[i] < tr2[k]) {tr[j] = tr2[i++];} else {tr[j] = tr2[k++];}}while (i <= m) {tr[j++] = tr2[i++];}while (k <= t) {tr[j++] = tr2[k++];}}/**快速排序。<br>冒泡排序的升级版,现在用的最多的排序方法<br>思想:选取pivot,将pivot调整到一个合理的位置,使得左边全部小于他,右边全部大于他;<br>时间复杂度:最好:O(nlogn) ,最坏:O(n^2) 。<br>空间复杂度:O(logn) 。<br>不稳定排序算法 */public static int[] quick_sort(int[] arr) {qsort(arr, 0, arr.length - 1);return arr;}/**快速排序优化方案*/public static int[] quick_sort2(int[] arr) {if (arr.length > 10) {qsort(arr, 0, arr.length - 1);} else {//快速排序适合大数组排序,如果是小数组,则效果可能没有简单插入排序来得好insertion_sort(arr);}return arr;}private static void qsort(int[] arr, int low, int high) {int pivot;if (low < high) {pivot = partition(arr, low, high);qsort(arr, low, pivot);qsort(arr, pivot + 1, high);}}private static int partition(int[] arr, int low, int high) {int pivotkey;pivotkey = arr[low];//选择pivot,此处可以优化while (low < high) {while (low < high && arr[high] >= pivotkey) {high--;}swap(arr, low, high);//交换,此处可以优化while (low < high && arr[low] <= pivotkey) {low++;}swap(arr, low, high);}return low;}
标签:
原文地址:http://www.cnblogs.com/baiqiantao/p/5452442.html