交换类排序总结
交换类排序总结
顾名思义,交换类排序,也就是通过一系列的交换元素过程,把原本逆序的元素交换为正确的顺序的排序方法
一.简单的交换类排序——冒泡排序
通过多趟的扫描,每趟扫描过程中,将相邻的元素中较大的交换至后面,这样每一趟结束时,最大的那个元素就“沉”到最后面,通过n-1趟的交换,直到只剩下一个元素在最前面,已经不需要交换了,完成排序
不过,冒泡排序写代码的时候要注意优化,下面是非优化版本
简单版本的冒泡排序
void Bubble_Sort(int a[],int n) { for (int i = 1; i <= n-1; i++) { for (int j = 0; j < n-i; j++) { if (a[j]>a[j+1]) { int temp=a[j+1]; a[j+1]=a[j]; a[j]=temp; } } } }
时间复杂度分析:这样看来,冒泡的最好时间复杂度和最坏时间复杂度都为O(n²);
最好的情况其实是可以优化的,那就是加入元素已经是排好序的话,我们可以用一个标志量来控制
void Bubble_Sort(int a[],int n) { bool change=true; for (int i = 1; i <= n-1&&change; i++) { change=false; for (int j = 0; j < n-i; j++) { if (a[j]>a[j+1]) { int temp=a[j+1]; a[j+1]=a[j]; a[j]=temp; change=true; } } } }
这样看来,冒泡排序的最好时间复杂度为O(n)了,外层循环实际上不进行了,只执行i=1的时候,因为元素是排好序的
最坏情况:仍然为O(n²)
二.快速排序(QuickSort)
我们可以回头过来看冒泡排序,通过它来理解所谓的比较排序到底是怎么一种思想,冒泡排序是通过不停地比较相邻的元素来排序,在一趟又一趟的扫描过程中完成排序,在这一过程中,比较是精髓和关键点,但是,在冒泡排序的比较过程中,我们可以发现,它每次只能比较相邻的元素,这样来看,效率是比较低的,能不能一次比较多个数来提高效率呢,快速排序的思想就是这样的,一趟比较多个元素
快速排序的思想
1.选取一个数作为标杆(选取第一个数),将数组中大于标杆数的元素都放到标杆数的右边,数组中小于标杆数的元素都放到标杆数的左边,记录下标杆数的位置
2.依据标杆数的位置,对标杆数左边的子数组重复第一步,直到左边只剩下一个数字
3.依据标杆数的位置,对标杆数左边的子数组重复第一步,直到左边只剩下一个数字
这样就完成了大名鼎鼎的快速排序,同时做到了一次排多个数字
一趟快速排序的实施步骤:
1.选取第一个数字作为标杆数,令low=其下标,令high=最后一个数字的下标,暂存变量x=a[low];
2从high到low遍历,将小于x的数字全部移到x的左边
3.从low到high遍历,将大于x的数字全部移到x的右边
4.当low=high的时候,停止遍历,最后返回标杆数x的位置
快速排序的实施步骤:
1.求得原数组标杆数的位置
2.利用标杆数位置,递归调用左边的子数组
3.利用标杆数位置,递归调用右边的子数组
具体代码如下:
int Quick_Sort_Once(int a[],int low,int high) { int x=a[low]; while(low<high) { while(low<high&&a[high]>=x) { high--; } if(low<high) { a[low]=a[high]; low++; } while(low<high&&a[low]<x) { low++; } if(low<high) { a[high]=a[low]; high--; } } a[low]=x; return low; } void Quick_Sort(int a[],int low,int high) { if(low<high) { int x=Quick_Sort_Once(a,low,high); Quick_Sort(a,low,x-1); Quick_Sort(a,x+1,high); } }
注意事项:注意Quick_Sort()函数中if(low<high)容易漏掉,这个必须有,不然,就会有无限递归调用,递归栈就会超出内存,程序崩溃
时间复杂度分析:
最坏的情况是:原数组本来就有序,这时候,左边子数组总是为空,右边子数组为n-1,所以总的时间复杂度为n-1+n-2+n-3+....+1=O(n²),即最坏的时间复杂度为O(n²);
最好的情况是:数组的第一个数正好是中间大的,这时候总的时间复杂度为:T(n)=O(n)+2T(n/2),根据这个式子可以推导出最好的时间复杂度为O(nlog2(n));
空间复杂度分析:
一般空间复杂度假如没有的递归的话为O(1),有递归的话那就看递归栈的深度了,递归栈的深度,那就看递归进层能有多深,这个递归明显是个二叉树式的递归,最好的情况是个满二叉树,因此树的深度就为递归栈的深度(最大只需要容纳几次push),树的深度为log2(n),所以空间复杂度为log2(n);
稳定性:不稳定
举个栗子:5644;
明显排序的时候后一个4是先填坑的,填到了5这个位置,这样一来他们的 顺序就颠倒了,所以是不稳定的,类似这样的情况时,他们都是不稳定的