总结一下常用的排序,冒泡排序,选择排序,快速排序
最近学习了几种排序。
(一)冒泡排序:
实现原理:
比如有一个数组 10, 43, 48, 1, 8, 3, 5, 7, 1, -21
第一次的第一轮:10小于43,所以10和43不交换位置;
第一次的第二轮:43小于48,所以43和48不交换位置;
第一次的第三轮:48大于1,所以48和1交换位置;变成了 10, 43, 1, 48, 8, 3, 5, 7, 1, -21
第一次的第四轮:48大于8,所以48和8交换位置;变成了 10, 43, 1, 8, 48, 3, 5, 7, 1, -21
第一次的第五轮:48大于3,所以48和3交换位置;变成了 10, 43, 1, 8, 3, 48, 5, 7, 1, -21
第一次的第六轮:48大于5,所以48和5交换位置;变成了 10, 43, 1, 8, 3, 5, 48, 7, 1, -21
........
以此类推,直到变成了 10, 43, 1, 8, 3, 5, 7, 1, -21,48。
为什么呢?因为48是该数组中最大的数,第一次就通过这个方法把48放到了数组的最后面,下次就不用再跟48比较了。
所以下一次就不用去跟最后的数比较了,因为最后的数是最大的数。
根据这个规则一直循环下去,经过数组中的数的数量减去1次,就完成了排序。
下面是根据c语言的代码(c中不允许在for循环中定义变量,除了c99标准):
#include<stdio.h> int main() { int A[10] = { 10,43,48,1,8,3,5,7,1,-21 }, t,i,j; for (i = 0; i < 10 - 1; i++) { for (j = 0; j < 10 - i - 1; j++) //因为后面j加1,所以先要减1 { if (A[j] > A[j + 1]) //前面的数与后面的数比较大小 { t = A[j]; A[j] = A[j + 1]; A[j + 1] = t; } } } for (i = 0; i < 10; i++) { printf("%d ", A[i]); } return 0; }
总结:冒泡排序是一种用时间换空间的排序方法,时间复杂度为O(N^2)。
(二)选择排序:
实现原理:
选择排序就是
将第一个数与他后面数中最小的数互换位置。
将第二个数与他后面数中最小的数互换位置。
将第三个数与他后面数中最小的数互换位置。
.......
直到将数组的数的数量减1的数与他后面数中最小的数互换位置。
选择排序代码(代码是用c++编译的,如果使用c的话就改一下头文件为#include<stdio.h>和for循环内的变量定义在外面):
#include<cstdio> int main() { int A[10] = { 10,43,48,1,8,3,5,7,1,-21 }, t, min; for (int i = 0; i<10 - 1; i++) { int index = i;//记录数的位置 min = A[i];//记录数的大小 for (int j = i + 1; j<10; j++) if (min>A[j]) //得到比他小的数,如果没有就是他自己 { min = A[j]; //得到最小数的大小 index = j; //得到最小数的位置 } t = A[i]; //交换位置,没有他自己,没有改变位置 A[i] = min; A[index] = t; } for (int i = 0; i<10; i++) printf("%d ", A[i]); return 0; }
总结:选择排序的平均时间复杂度为O(N^2)。
注:以上两种排序方法因为时间复杂度较大,所以现在很少使用。
(三)快速排序:
实现原理:
以下面代码为例:
将第一个数作为key值保存,也就是10。
然后从右边开始寻找,进入第一个循环,依次向左移,直到找到比key值小的数。
右边第一个数-21比10要小,所以退出第一个循环,第一个值为-21。数组变成 -21, 43, 48, 1, 8, 3, 5, 7, 1, -21。
然后从左边开始寻找,进入第一个循环,依次向左移,直到找到比key值小的数。
左边第一个数10与key值10相等,继续循环。
左边第二个数43比10要大,所以退出第二个循环,数组变成 -21, 43, 48, 1, 8, 3, 5, 7, 1, 43。
因为左边和右边位置还不相同,所以重新进入第一个循环第一个循环(i<j的意义)。
.......
以此类推
一直到数组为 -21, 1, 7, 1, 8, 3, 5, 7, 48, 43。
退出循环。此时i等于j(位置相同)。
i和j在第二个7的位置(如果不懂可以在每次数组循环后打印一次数组查看数组顺序,和查看一下i和j的位置)。
然后第二个7的位置上的值为10。
此时10的左边的数一定小于10,10右边的数一定大于10。
然后左边的数和右边的数分别进入递归,根据这种思想方法去排序,直到完成排序退出递归。
代码如下:
#include<cstdio> using namespace std; void QSort(int left, int right, int *A) { if (left > right)return;//直到数组中只有唯一一个数,退出递归。 int i = left; int j = right; int key = A[left]; while (i<j) { while (i<j&&key <= A[j])j--;//从右边开始,找到比key小的数。 A[i] = A[j]; while (i<j&&key >= A[i])i++;//从左边开始,找到比key大的数。 A[j] = A[i]; } A[i] = key;//重新获得key的值。 QSort(left, i - 1, A);//排列左边的数。 QSort(i + 1, right, A);//排列右边的数。 } int main() { int A[10] = { 10,43,48,1,8,3,5,7,1,-21 }; QSort(0, 9, A); for (int i = 0; i<10; i++) printf("%d ", A[i]); return 0; }
总结:快速排序的时间复杂度为O(N),相比于前两种排序的使用时间要少很多,在很多复杂的排序中经常用到。
**以上有什么错误还望指出,希望我们共同学习。**