插入排序 | 选择排序 | 冒泡排序
插入排序
将待排序的数据插入到已经排好序的数列中去。过程:依次与已排好序中的数据进行比较,从而找到适合自己的位置,直至插入全部待排序的数据为止。
例如:arr = [2 , 5 , 3 , 1 , 6 ]
伪代码:
//写法1(最好不要这样写) 这样会让待排序数据与有序区所有数据两两比较,不会提前终止; for (i=0;j<arr.length;i++) { for(j=i;j>0;j--) { if (arr[j]<arr[j-1]) //如果后面的数更大 exchange; //交换arr[j]和arr[j-1]的值 } } //写法2(这样写好些) for (i=0;j<arr.length;i++) { //这样写的好处是可以提前终止比较;因为前面是已排好序的数据,只要待排序数据不小于有序区最后一个数据,则不用继续比较了; for(j=i;j>0&&arr[j]<arr[j-1];j--) { exchange; //交换arr[j]和arr[j-1]的值 } }
初始状态:无序区就是全部的数据;有序区是空的[ ];
外层for循环的意义:取本次待排序的数据。例如第一次取arr[0];第二次取arr[1];
内层for循环的意义:依次将待排序的数据与已排好序的数据进行比较,直到找打适合它的位置;
举个实例,比如我们打牌一人一张摸牌的时候:
来第一张牌时直接放好;
来第二张牌时和第一张比较,放好;
第三张牌来时,和手上的2张的最后一张比较,比最后一张大,那就直接把第三章牌放最后就好了,不用再和前面的比较了;
选择排序
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
伪代码:
for (var i = 0; i < len - 1; i++) { minIndex = i; //假设这个索引的值就是最小的 for (var j = i + 1; j < len; j++) { if (arr[j] < arr[minIndex]) { // 寻找最小的数的索引 minIndex = j; // 将最小数的索引保存 } } temp = arr[i]; arr[i] = arr[minIndex]; //交换arr[i]和arr[minIndex] arr[minIndex] = temp; }
初始状态:无序区就是全部的数据;有序区是空的[ ];
外层for循环的意义:取无序区第一个数据,假设它就是无序区里最小的数据;注意条件是len-1!每轮从无序区取出了最小的数挪到前面,那么最后一个数就不用排了。
内层for循环的意义:用外层循环取到的数据,依次和无序区的数据进行比较,记录下最小的那个数值的索引;在内层循环结束后,将外层循环取到的数据和最小的数据交换;直到排完所有无序区的数据;
插入排序和选择排序的比较:
1、流程不一样;
插入排序:依次进行两两比较,不合适就交换位置,直到找到目标位置;
选择排序:通过比较找到目标位置,再直接交换,相当于一步到位; 交换的次数少;
2、在数据量大的情况下,插入排序比选择排序效率更高。
相比于选择排序,插入排序的一个优点是提前终止,不用遍历整个数组,因此,插入排序应该要比选择排序的效率更加的高效;
冒泡排序
每一轮排序后将最大的数排到最后去;
依次比较两个相邻的数,将大的数放后面。那么在经过一轮排序后,最大的数就移到最后去了;
所以第二轮排序,最后一个数就不用再参与比较了;
[2,5,3,1,6] for (int i = 0; i < len-1; i++) { //为什么是len-1?因为len个数,只需要排len-1次就好了。 //对待排序序列进行冒泡排序 for (int j = 0; j < len - i - 1; j++) { //为什么是N-i-1?因为if判断写的是和j+1比较;当i=0时,最后一轮比较的是a[3]和a[4] //相邻元素进行比较,当顺序不正确时,交换位置 if (a[j] > a[j + 1]) { exchange; } } }
外层for循环的意义:控制内层循环要比较的数据;比如第一轮要比较完所有的数据,也就是比较到len-1(数组索引从0开始);第二轮则不用比较最后一个数据了,比较到len-2就行;
内层for循环的意义:依次比较两两相邻的数据,直至把最大的数排最后去;
End.