排序算法-------交换排序
2018-03-12 16:36
323 查看
1. 冒泡排序
冒泡排序之前已经熟悉其过程,不在画图,直接上代码void Bubble(DataType* a,size_t n) { assert(a != NULL && n > 0); for(int end = n;end > 0;--end) { int flag = 0; for(int i = 1;i < end;++i) { if(a[i-1] > a[i]) { Swap(&a[i-1],&a[i]); flag=1; } } if(flag == 0) { break; } } }
2.快速排序
三种方法
1.左右指针法
(1)从数组当中选取一个关键元素key;(2)begin在数组最左边,从数组的左边走,直到找到比key大的数
(3)end在数组最右边,从右向左走,直到找到比key小的数
(4)交换begin和end所在位置的值
(5)当begin和end走到相同位置时,交换关键元素key和begin位置的元素
(6)此时一趟排序完成,以begin为分界线,划分为左区间和右区间,在进行左区间和右区间的排序
(7)当左区间右区间任意一个不存在或者只剩一个元素时,排序即可完成
代码:
//左右指针法 int PartSort1(DataType* a1, int left, int right) { assert(a); DataType key = a[right]; int begin = left, end = right; while (begin < end) { //选出比key大的数据 while (begin < end && a[begin] <= key) ++begin; //选出比key小的数 while (begin < end && a[end] >= key) --end; //交换begin和end两个位置的值 Swap(&a[begin], &a[end]); } //注意这里是换a[right]和a[begin]的值 Swap(&a[begin], &a[right]); return begin; } //快速排序 void QuickSort(DataType* a, int left, int right) { assert(a); if (right - left > 10) { InsertSort(a, right - left + 1); } else { //划分区间返回条件,当左区间或右区间不存在,或只有一个数时,开始返回 if (left >= right) return; int div = PartSort1(a, left, right); //去左区间排序 QuickSort(a, left, div - 1); //去右区间排序 QuickSort(a, div + 1, right); } }
2.挖坑法
(1)从数组当中选取一个关键元素key,以key的位置作为第一个坑index(2)begin在数组最左边,从数组的左边走,直到找到比key大的数,将index的元素付给begin,a[index]=a[begin],此时begin作为新的坑,index=begin
(3)end在数组最右边,从右向左走,直到找到比key小的数a[end],将end的元素给坑index,a[index]=a[end],此时end作为新的坑
(4)当begin和end走到相同位置,此时坑就在begin位置,将key填入坑
(5)此时一趟排序完成,以begin为分界线,划分为左区间和右区间,在进行左区间和右区间的排序
(6)当左区间右区间任意一个不存在或者只剩一个元素时,排序即可完成
代码:
//填坑法 int PartSort2(DataType* a1, int left, int right) { assert(a); DataType key = a[right]; int begin = left, end = right; while (begin < end) { //坑在end,找到比key大的值,将数据填入坑 while (begin < end && a[begin] <= key) ++begin; a[end] = a[begin]; //此时坑在begin处,找到比key小的值,将数据填入坑 while (begin < end && a[end] >= key) --end; a[begin] = a[end]; } //当begin和end在同一位置处,将key填在坑处 a[begin] = key; return begin; } //快速排序 void QuickSort(DataType* a, int left, int right) { assert(a); if (right - left > 10) { InsertSort(a, right - left + 1); } else { //划分区间返回条件,当左区间或右区间不存在,或只有一个数时,开始返回 if (left >= right) return; int div = PartSort2(a, left, right); //去左区间排序 QuickSort(a, left, div - 1); //去右区间排序 QuickSort(a, div + 1, right); } }
3.前后指针法
(1)选取一个关键元素可以,并定义两个指针,int cur=left;int prev=cur-1;(2)a[cur] >= key,cur++
(3)a[cur] < key,cur停下来,prev++,如果prev != cur,则交换两位置的数值;
(4)当cur走到数组的最后,表示一趟已经结束,将cur的值和prev的后一位置进行交换
(5)以prev为界限,划分为左区间和右区间
(6)当左区间或右区间不存在,或只有一个数时,排序即完成
代码
//前后指针 int PartSort3(DataType* a1, int left, int right) { assert(a); DataType key = a[right]; int cur = left; int prev = left - 1; while (cur < right) { //当a[cur]比key小,prev走,并且当prev不在同一位置上时,进行交换 if ( a[cur] < key) { ++prev; if (cur!=prev) Swap(&a[cur], &a[prev]); } //不管比key小还是大,cur继续向后走 ++cur; } //当cur走到数组的最后,表示一趟已经结束,将cur的值和prev的后一位置进行交换 Swap(&a[++prev], &a[right]); return prev;//以prev为界限,划分为左区间和右区间 } //快速排序 void QuickSort(DataType* a1, int left, int right) { assert(a); if (right - left > 10) { InsertSort(a, right - left + 1); } else { //划分区间返回条件,当左区间或右区间不存在,或只有一个数时,开始返回 if (left >= right) return; int div = PartSort2(a, left, right); //去左区间排序 QuickSort(a, left, div - 1); //去右区间排序 QuickSort(a, div + 1, right); } }
快速排序的优化
1. 小区间优化当区间中元素数量较小时在用递归反而会使效率降低,当区间元素数据较小,就越接近排序,此时,我们采用直接插入排序进一步提高效率
2. 随机值法
在选key时,在数组中随机选取一个数作为key进行排序;
代码:
sand(time(0)); int index = rand()%(right - left + 1);//随机产生下标 int key = a[index];
注意:这种方法并不实用,随机产生的key是大还是小并不确定,key选取的不合适反而会降低效率
3. 三数取中法
选取数组的首元素a[0]、尾元素a[n-1]以及中间元素a[(0+n-1)/2]选出三者的中位数作为key值。这时候选出来的key可以保证绝对不是最大数或最小数(如果三个数都是相同的,那key还是最大或最小值,不过出现这种情况概率及其低)
int Getkey(DataType* a, int left, int right) { assert(a); DataType mid = left + ((right - left) >> 1); // mid恰好为key //情况1:left <mid ,mid <right //情况2:left>mid,mid > right if ((a[left] < a[mid] && a[mid] < a[right]) || (a[right] < a[mid] && a[mid] < a[left])) { return mid; } //left为key //情况1:left > right,left < mid //情况2:left >mid, left < right else if ((a[right] < a[left] && a[left] < a[mid]) || (a[mid] < a[left] && a[left] < a[right])) { return left; } else { //right为key //情况1:right > left ,right < mid //情况2:right < left,right >mid return right; } }
快速排序的非递归
递归是依赖于函数栈帧,那么我们可以用我们的栈去模拟实现函数的递归调用void QuickSortNonR(DataType* a, int left, int right) { assert(a); Stack s; StackInit(&s); //先将左右区间进行入栈 StackPush(&s, left); StackPush(&s, right); while (left < right && StackEmpty(&s) != 0) { //从栈中取出区间坐标 int end = StackTop(&s); StackPop(&s); int begin = StackTop(&s); StackPop(&s); //计算下一次区间的临界值 int div = PartSort1(a, begin, end); //如果区间内有两个数以上,进行入栈 if (begin < div-1 ) { StackPush(&s, begin); StackPush(&s, div-1 ); } if (div+1 < end) { StackPush(&s, div+1 ); StackPush(&s, end); } } }
两种算法分析
稳定性
冒泡排序:稳定算法,在单趟排序和多趟排序的过程中,元素的相对位置都不会发生变化快速排序:不稳定算法,三种方法实现过程中都存在元素交换,相对位置会发生改变
时间复杂度
冒泡排序:O(n2n2)快速排序:经优化过后为O(nlgn),最坏的情况为O(n2n2)
空间复杂度
冒泡排序:O(1)快速排序:O(lgn)
相关文章推荐
- 排序算法--交换排序(冒泡排序、快速排序、随机快速排序)java实现
- 算法 排序算法之交换排序--冒泡排序和快速排序
- 常见排序算法:交换排序
- 【数据结构】排序算法(二)之交换排序之快速排序(QuickSort)
- 排序算法(三) - 交换排序
- 排序算法整理(C++):插入排序、交换排序、选择排序、归并排序
- 排序算法--交换排序之冒泡
- 排序算法基础篇交换排序之冒泡排序
- 【数据结构】排序算法(二)之交换排序之快速排序(QuickSort)
- 软考二进宫-排序算法-交换排序
- 实用的排序算法 - 交换排序
- 排序算法(三)、交换排序 —— 冒泡排序 和 快速排序
- 经常使用排序算法实现[交换排序之冒泡排序、高速排序]
- 排序算法-heap排序-改良的交换排序算法
- 8)排序①排序算法之交换排序[2]快速排序
- 排序算法复习——交换类排序
- 排序算法---交换排序( java)
- 各种排序算法汇总(交换排序:冒泡排序、快速排序)
- 排序算法之交换排序
- 排序算法四:交换排序之冒泡排序