排序I
来源:互联网 发布:七月算法视频pan 编辑:程序博客网 时间:2024/06/04 00:35
冒泡排序
冒泡排序的基本思想是两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
标准代码
package com.weixuan.sort.bubble;public class BubbleSort { public static void bubbleSort(int[] data) { for (int i = 0; i < data.length; i++) { for (int j = data.length - 2; j >= i; j--) { if (data[j] > data[j + 1]) swap(data, j, j + 1); } System.out.println("第 " + (i+1) + " 次"); printArray(data); System.out.println("\n"); } } private static void swap(int[] data, int j, int i) { if (data == null || data.length <= 0) return; int temp = data[j]; data[j] = data[i]; data[i] = temp; } public static void printArray(int[] array) { for (int i = 0; i < array.length; i++) System.out.print(array[i] + "\t"); }}
过程详解 – {9,1,5,8,3,7,4,6,2}
第一趟:i==0,j = 8,j从j = 8 反循环遍历到j = 0,逐个比较,直到找到最小值放在i=0的位置上。
2 < 6 : 9, 1, 5, 8, 3, 7, 4, 2, 6 j = 8
2 < 4 : 9, 1, 5, 8, 3, 7, 2, 4, 6 j = 7
2 < 7 : 9, 1, 5, 8, 3, 2, 7, 4, 6 j = 6
2 < 3 : 9, 1, 5, 8, 2, 3, 7, 4, 6 j = 5
2 < 8 : 9, 1, 5, 2, 8, 3, 7, 4, 6 j = 4
2 < 5 : 9, 1, 2, 5, 8, 3, 7, 4, 6 j = 3
1 < 2<不交换> : 9, 1, 2, 5, 8, 3, 7, 4, 6 j = 2
1 < 9 : 1, 9, 2, 5, 8, 3, 7, 4, 6 j = 1
第一趟的结果就是:
1, 9, 2, 5, 8, 3, 7, 4, 6
第二趟:i==1,j = 8,j从j = 8 反循环遍历到j = 1,逐个比较,直到找到次最小值放在i=1的位置上。
4 < 6<不交换> : 1, 9, 2, 5, 8, 3, 7, 4, 6 j = 8
4 < 7 : 1, 9, 2, 5, 8, 3, 4, 7, 6 j = 7
3 < 4<不交换> : 1, 9, 2, 5, 8, 3, 4, 7, 6 j = 6
3 < 8 : 1, 9, 2, 5, 3, 8, 4, 7, 6 j = 5
3 < 5 : 1, 9, 2, 3, 5, 8, 7, 4, 6 j = 4
2 < 3<不交换> : 1, 9, 2, 3, 5, 8, 7, 4, 6 j = 2
2 < 9 : 1, 2, 9, 3, 5, 8, 7, 4, 6 j = 2
1 < 2<不交换> : 1, 2, 9, 3, 5, 8, 7, 4, 6 j = 1
第二趟的结果就是:
1, 2, 9, 3, 5, 8, 7, 4, 6
后面的同理
第 1 次1 9 2 5 8 3 7 4 6 第 2 次1 2 9 3 5 8 4 7 6 第 3 次1 2 3 9 4 5 8 6 7 第 4 次1 2 3 4 9 5 6 8 7 第 5 次1 2 3 4 5 9 6 7 8 第 6 次1 2 3 4 5 6 9 7 8 第 7 次1 2 3 4 5 6 7 9 8 第 8 次1 2 3 4 5 6 7 8 9 第 9 次1 2 3 4 5 6 7 8 9
可以优化的地方
假设有序列{2,1,3,4,5,6,7,8,9},除了2和1需要交换之外,其他的已经有序了,无需再次循环。
优化之前
输出
第 1 次1 2 3 4 5 6 7 8 9 第 2 次1 2 3 4 5 6 7 8 9 第 3 次1 2 3 4 5 6 7 8 9 第 4 次1 2 3 4 5 6 7 8 9 第 5 次1 2 3 4 5 6 7 8 9 第 6 次1 2 3 4 5 6 7 8 9 第 7 次1 2 3 4 5 6 7 8 9 第 8 次1 2 3 4 5 6 7 8 9 第 9 次1 2 3 4 5 6 7 8 9
可以看到,从第二次开始就是已经有序了,但是这个傻瓜式的程序还循环了7次!!!
优化的代码
public static void bubbleSortSuper(int[] data) { boolean flag = true; for (int i = 0; i < data.length && flag; i++) { flag = false;/*初始为false*/ for (int j = data.length - 2; j >= i; j--) { if (data[j] > data[j + 1]) { swap(data, j, j + 1); flag = true; // 有数据交换,flag = true } } System.out.println("第 " + (i + 1) + " 次"); printArray(data); System.out.println("\n"); } }
输出,只循环了两次
第 1 次1 2 3 4 5 6 7 8 9 第 2 次1 2 3 4 5 6 7 8 9
性能分析 序列长度为N
最好的情况:序列本身有序,那么就是
最差的情况:序列逆序,需要比较
基本也是这个数量级的交换,所以时间复杂度是
快速排序
基本思想:每一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录关键字小,然后分别对这两部分进行排序,打到整个序列有序的目的。
package com.weixuan.sort.quicksort;public class QuickSort { private static void swap(int[] data, int j, int i) { if (data == null || data.length <= 0) return; int temp = data[j]; data[j] = data[i]; data[i] = temp; } public static void printArray(int[] array) { for (int i = 0; i < array.length; i++) System.out.print(array[i] + "\t"); } private static int partition(int[] data, int low, int high) { int pivot = data[low];// 轴值 while (low < high) { while (low < high && data[high] >= pivot) high--; // 交换 swap(data, low, high); while (low < high && data[low] <= pivot) low++; // 交换 swap(data, low, high); } System.out.println("------"); printArray(data); System.out.println("------"); return low; } private static void quickSort(int[] data, int low, int high) { if (low < high) { int k = partition(data, low, high); quickSort(data, low, k - 1); quickSort(data, k + 1, high); } } public static void quickSort(int[] data) { quickSort(data, 0, data.length - 1); }}
排序过程 – {50,10,90,30,70,40,80,60,20}
第一趟:
初始pivot = 50,low = 0,high = 8,data[low] = 50,data[high] = 20
data[high] = 20 < pivot ,交换,但是low和high没有变,直接跳出循环。
20,10,90,30,70,40,80,60,50 [此时 low = 0,high = 8]
data[low] = 20 < pivot,low++,只到low = 2,data[low] = 90 >pivot,退出循环,交换
20,10,50,30,70,40,80,60,90 [此时 low = 2,high = 8]
low = 2 < high = 8 ,继续大循环
初始pivot = 50,low = 2,high = 8
data[high]=90 > pivot,high–,只到high = 5,data[high] = 40 < pivot,跳出循环,交换
20,10,40,30,70,50,80,60,90 [此时 low = 2,high = 5]
data[low] = 40 < pivot,low++,只到low = 4,data[low] = 70 > pivot,跳出循环,交换
20,10,40,30,50,70,80,60,90 [此时 low = 4,high = 5]
low = 4 < high = 5 ,继续大循环
low = high = 4,退出循环,
返回low = 4
第一趟的结果就是
[20,10,40,30,50,70,80,60,90]
然后就是递归调用
对[20,10,40,30] 和 [70,80,60,90]分别执行第一趟的操作。
性能分析
快速排序的事件性能取决于快速排序递归的深度,上述的递归过程第一个关键字是50,正好是待排序序列的中间值,因此整个树是平衡的。此时性能最好。
在最优情况下,长度为n的序列递归的深度是
也就是说,在最优情况下,时间复杂度为
最差情况下,序列为有序或者逆序,此时需要n-1次递归调用,第i次划分需要n-i次比较才能找到第i个记录,因此比较的次数是
时间复杂度是
由于快速排序的关键字比较是跳跃进行的,所以是不稳定的排序方法。
快速排序优化
快排最好情况是第一个轴值就是整个序列的中间值,也就是说跨拍的性能瓶颈在与pivot在序列中的位置。
那么可以在low与hight之间随机选择一个数,随机选取轴值法。这样有些碰运气的感觉。
更优化的是三数取中法,即取三个关键字先进行排序,将中间数作为轴值,一般是取左端,右端和中间三个数。
- 选择合适的轴值
private static int partition(int[] data, int low, int high) { //int pivot = data[low];// 轴值 int pivot = medianOfThree(data,low,high); while (low < high) { while (low < high && data[high] >= pivot) high--; // 交换 swap(data, low, high); while (low < high && data[low] <= pivot) low++; // 交换 swap(data, low, high); } System.out.println("------"); printArray(data); System.out.println("------"); return low; } private static void quickSort(int[] data, int low, int high) { if (low < high) { int k = partition(data, low, high); quickSort(data, low, k - 1); quickSort(data, k + 1, high); } } public static void quickSort(int[] data) { quickSort(data, 0, data.length - 1); } private static int medianOfThree(int[] data, int low, int high) { int pivot; int media = low + (high - low) / 2; // 保证左端较小 if (data[low] > data[high]) swap(data, low, high); // 保证中间较小 if (data[media] > data[high]) swap(data, high, media); // 保证左端较小 if (data[media] > data[low]) swap(data, media, low); pivot = data[low]; return pivot; }
- 避免不必要的交换
private static void quickSort(int[] data, int low, int high) { if (low < high) { // int k = partition(data, low, high); int k = partitionSuper(data, low, high); quickSort(data, low, k - 1); quickSort(data, k + 1, high); } } public static void quickSort(int[] data) { quickSort(data, 0, data.length - 1); } private static int medianOfThree(int[] data, int low, int high) { int pivot; int media = low + (high - low) / 2; // 保证左端较小 if (data[low] > data[high]) swap(data, low, high); // 保证中间较小 if (data[media] > data[high]) swap(data, high, media); // 保证左端较小 if (data[media] > data[low]) swap(data, media, low); pivot = data[low]; return pivot; } private static int partitionSuper(int[] data, int low, int high) { int pivot = medianOfThree(data, low, high); while (low < high) { while (low < high && data[high] >= pivot) high--; // 将交换改为替换 // swap(data, low, high); data[low] = data[high]; while (low < high && data[low] <= pivot) low++; // 将交换改为替换 // swap(data, low, high); data[high] = data[low]; } return low; }
选择排序
简单选择排序的基本思想是每一趟在
package com.weixuan.sort.select;public class SelectSort { private static void swap(int[] data, int j, int i) { if (data == null || data.length <= 0) return; int temp = data[j]; data[j] = data[i]; data[i] = temp; } public static void printArray(int[] array) { for (int i = 0; i < array.length; i++) System.out.print(array[i] + "\t"); } public static void selectSort(int[] data) { int minIndex; for (int i = 0; i < data.length; i++) { minIndex = i; for (int j = i + 1; j < data.length; j++) { if (data[minIndex] > data[j]) minIndex = j; } if (i != minIndex) //找到最小值 swap(data, i, minIndex); } }}
过程说明 – {9,1,5,8,3,7,4,6,2}
i = 0,minIndex = 0,j = 1
data[minIndex] > data[1],minIndex = 1, (比较8次)
minIndex = 1,j = 2…一直循环到j = 8
1,9,5,8,3,7,4,6,2
i = 1,minIndex = 1,j = 2
在剩余的部分找最小值,交换 (比较7次)
1,2,5,8,3,7,4,6,9
i = 2,minIndex = 1,j = 3
在剩余的部分找最小值,交换
1,2,3,8,5,7,4,6,9
i = 3,minIndex = 1,j = 4
在剩余的部分找最小值,交换
1,2,3,4,5,7,8,6,9
i = 4,minIndex = 1,j = 5
在剩余的部分找最小值,交换
1,2,3,4,5,6,8,7,9
i = 5,minIndex = 1,j = 6
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9
i = 6,minIndex = 1,j = 7
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9
i = 7,minIndex = 1,j = 1
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9
i = 8,minIndex = 1,j = 1
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9
性能分析
- 无论最好最差情况,比较次数是一样多。第i趟需要进行n-i次关键字比较,总的比较次数
∑i=0n−1(N−i)=1+2+3+...+(n−1)=n(n−1)2 - 交换次数,最好时,本身有序,交换0次,最差的时候,逆序,交换n-i次
- 时间复杂度是
O(N2)
- 排序I
- 排序I
- C++快速排序I
- i os 排序
- 问题 I 数列排序
- 【SSLGZ 1271】 排序I
- 数据结构—排序I
- 数组I冒泡法排序
- Java实现-整数排序i
- 搜索旋转排序数组I
- Problem I: 冒泡排序法排序
- 已排序的i个最大数
- 快速排序法 为什么i=j???
- 学习笔记 I——排序
- 数据结构+算法系列四:I 堆排序
- 数据结构+算法系列五:I 快速排序
- Sorting Problem I NOJ1870 水 冒泡排序
- 排序 Swap(0, i) 最小次数
- 华为上机题:任意输入一个数是1到9做运算的结果,求有多少种可能性
- Spring Auto proxy creator example
- BC - Reflect(欧拉函数)
- Android之旅:梦想、学习、坚持、自信、淡定
- 变量的间接取值和拼接后的间接取值
- 排序I
- Exynos4412 Andriod4.4 源码编译生成SDK
- Comet:基于 HTTP 长连接的“服务器推”技术
- 通达OA破解版下载|通达OA2015破解版 可用|通达oa2015破解补丁
- 网络流之最大流(关于poj1273)
- Hibernate批量操作(JDBC批量操作)
- BestCoder Round #54
- Hibernate二级缓存 ---- 最佳实践
- Codeforces Gym 100345H Settling the Universe Up Bitset+倒推