排序算法之冒泡、插入、选择排序
简介:
冒泡排序(Bubble Sort)是一种简单的排序算法,它通过依次比较相邻的两个元素,判断两个元素是否满足大小关系,如果不满足则交换两个元素,每一次冒泡会让至少一个元素移动到它应该在的位置,这样n次冒泡就完成了n个数据的排序工作。这个算法的排序过程与气泡从水中往上冒的情况很相似,故美其名曰:冒泡排序。
作者:geekymv
https://www.bilibili.com/read/cv8872800/
出处: bilibili
逻辑:
比较两个相邻的元素,将值大的元素交换到右边。(从小到大排列)
代码实现:
例如数据如下:
1,23,2,12,11,2,5
排序后结果:
1,2,2,5,11,12,23
首先遍历数据集合:
public static void insertinSort2(int[] intArray){ // 因为第一个不参与冒牌默认已经冒泡 for (int i = 1; i < intArray.length; i++) { } System.out.println(Arrays.toString(intArray)); }
然后根据拿到的数据遍历已经排好的数据,进行对比,如果小于则交换排列后的位置。代码如下:
// 先找大的放到最后面 for (int i = 0; i < intArray.length-1; i++) { for (int j=0; j <intArray.length-1 ; j++) { if(intArray[j]>intArray[j+1]){ int a1 = intArray[j]; intArray[j]= intArray[j+1]; intArray[j+1]=a1; } } System.out.println(Arrays.toString(intArray)); }
执行代码后发现有多条重复排序,也就是多余对比。
[1, 2, 12, 11, 2, 5, 23] [1, 2, 11, 2, 5, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23]
打印结果如上。
首先把选取一个元素放到首位,然后和剩余数组数据进行遍历与该值比较。如果该值后面的数大于该数字,则进行位置互换。
我们可以把打印数组的输出语句放在第二个for循环,可以看到进行了多少次遍历。
// 先找大的放到最后面 for (int i = 0; i < intArray.length-1; i++) { for (int j=0; j <intArray.length-1 ; j++) { if(intArray[j]>intArray[j+1]){ int a1 = intArray[j]; intArray[j]= intArray[j+1]; intArray[j+1]=a1; } System.out.println(Arrays.toString(intArray)); } }
如上可以看到遍历了 array.length-1 * array.length-1 次。其实我们在冒泡的时候,每次冒泡之后都会完成一个数的排列。也就是后面冒泡不需要全量,是递减的进行冒泡。所以代码可以这样改。
// 先找大的放到最后面 for (int i = 0; i < intArray.length-1; i++) { for (int j=0; j <intArray.length-1-i ; j++) { if(intArray[j]>intArray[j+1]){ int a1 = intArray[j]; intArray[j]= intArray[j+1]; intArray[j+1]=a1; } System.out.println(Arrays.toString(intArray)); } }
第二次遍历的时候,减去i,也就是已经冒泡排序的个数。这样我数组长度为7,冒泡次数就是6,5,4,3,2,1共21次。比之前36次少了15次。
打印后结果为:
[1, 23, 2, 12, 11, 2, 5] [1, 2, 23, 12, 11, 2, 5] [1, 2, 12, 23, 11, 2, 5] [1, 2, 12, 11, 23, 2, 5] ...... [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23] [1, 2, 2, 5, 11, 12, 23]
还有另外一个问题,也就是排序成功后,依然在进行排序。如上打印所示,最后几次排序结果是一样的。也就是重复排序了。
我们可以加个标识,是否交换元素,如果没有交换元素则代表排序成功了。就不必进行排序了。代码如下:
for (int i = 0; i < intArray.length-1; i++) { boolean flag = false; for (int j=0; j <intArray.length-1-i ; j++) { if(intArray[j]>intArray[j+1]){ int a1 = intArray[j]; intArray[j]= intArray[j+1]; intArray[j+1]=a1; flag = true; } System.out.println(Arrays.toString(intArray)); } if(!flag){ break; } }
打印之后可以看到排序次数明显少了三次。这个只是减少外层循环次数。还是多出来的打印是因为内存需要遍历整个数组。

插入排序
for (int i = 1; i < A.length; i++) { int c = A[i]; int j = i; System.out.println("~~~~~"+ c); for (; j >0 && A[j-1]>c ; j--) { A[j]=A[j-1]; System.out.println(Arrays.toString(A)); } A[j] = c; }
同样的上面数组,这个方法冒泡十次就可以排好。
如下图所示:提出来一个数字,然后整体后移,这个数字放到前面。

y-1的数字是跟y也就是选中的数字比大小。
记得刚开始写的时候记不起来,写的程序跟课程上的就一点出入。

执行出来结果天差地别,就很疑惑为什么同样的判断放到表达式里面外面可以,里面却不行。
后来经过折腾发现。如果表达式放在for循环上可以理解为“门”,上面那种可以拦截不进入for循环,下面的则会进入for循环在判断。可以根据下面的代码进行理解。

选择排序:
简介:
选择排序:扫描序列,找到最小的元素与首位未排序的元素交换位置。接着循环这个动作直到最后一个元素,结束排序得到一个有序的序列。
代码实现:
例如数据如下:
1,23,2,12,11,2,5 排序后结果: 1,2,2,5,11,12,23
首先不变的就是遍历整个数组
for (int i = 0; i < A.length; i++) {
}
然后进行整个数组获取最小的元素。新起一个方法获取最小的元素下标。
private static int getMinIndex(int[] a, int startIndex) {
int minIndex = startIndex;
for (int i = startIndex+1; i < a.length; i++) {
if(a[i]<a[minIndex]){
minIndex=i;
}
}
return minIndex;
}
然后再交换元素:
public static void selectSort(int[] A){
for (int i = 0; i < A.length; i++) {
int minIndex = getMinIndex(A,i);
int c =A[i];
A[i]=A[minIndex];
A[minIndex] = c;
}
}
private static int getMinIndex(int[] a, int startIndex) {
int minIndex = startIndex;
for (int i = startIndex+1; i < a.length; i++) {
if(a[i]<a[minIndex]){
minIndex=i;
}
}
return minIndex;
}
冒泡算法对比相邻两个数,把最大的放在右边。一直换到最后。就冒出了最大数。如下图所示:

冒泡排序一直在交换,所以一直操作CPU写,所以耗时更长。


浙公网安备 33010602011771号