果树电动剪刀价格:【排序结构2】交换排序

来源:百度文库 编辑:中财网 时间:2024/05/15 19:52:15

1、起泡排序 O(N^2)

起泡排序的过程很简单,首先将第一个关键字和第二个关键字比较,若为逆序,则将两个记录交换。然后再用第二个关键字和第三个关键字比较,以此类推,知道第n-1个关键字和第n个比较完,这样最大的关键字将被交换到第n个位置上。这个过程称做第一趟气泡排序。然后对前n-1进行第二趟气泡排序,将第二大的关键字交换到第n-1个位置上。当第n-1趟气泡排序完成之后,有序序列也就随之产生了。

Cpp代码
  1. #include
  2. /**************************
  3. * 起泡排序 Bubble Sort *
  4. **************************/
  5. class BubbleSort{
  6. public:
  7. static void inc_sort(int keys[],int size);
  8. };
  9. void BubbleSort :: inc_sort(int keys[], int size){
  10. for(int i=size-1;i>=0;i--)
  11. for(int j=0;j
  12. if(keys[j]>keys[j+1]){
  13. int temp=keys[j];
  14. keys[j]=keys[j+1];
  15. keys[j+1]=temp;
  16. }
  17. }
  18. for(int k=0;k
  19. cout<
  20. cout<
  21. }
  22. //Test BubbleSort
  23. void main(){
  24. int raw[]={49,38,65,97,76,13,27,49};
  25. int size=sizeof(raw)/sizeof(int);
  26. BubbleSort::inc_sort(raw,size);
  27. }
#include/************************** * 起泡排序 Bubble Sort   *  **************************/  class BubbleSort{public:static void inc_sort(int keys[],int size);};void BubbleSort :: inc_sort(int keys[], int size){for(int i=size-1;i>=0;i--)for(int j=0;jkeys[j+1]){int temp=keys[j];keys[j]=keys[j+1];keys[j+1]=temp;}}for(int k=0;k

显然,气泡排序的时间复杂度为O(N^2),其空间复杂度为O(1) ,而且是稳定的。

2、快速排序 O(N*logN)

快速排序是对起泡排序的一种改进。它的基本思想就是:通过一趟排序将待排记录分割成独立的两个部分,其中一个部分的关键字都比另一个部分关键字小,然后可以分别再对这两个部分继续快排,已达到整个序列有序。

具体的做法是:对待排序列keys[n]确定两个指针(low=0,high=n-1)。然后取第一个关键字keys[0]作为pivotkey(枢轴)。首先从high所指的位置起向前搜索找到第一个关键字小于pivotkey的记录,并将这个记录的关键字与pivotkey交换。然后从low所指的位置向后搜索,找到第一个关键字大于pivotkey的记录,并交换。轮流重复这两个步骤直到low=high位置。这样一个过程我们叫做一次快排(又叫一次划分)。

对划分后的序列的两个部分继续分别快排,知道所有序列有序位置,整个过程就是快排。

Cpp代码
  1. #include
  2. class QuickSort{
  3. private:
  4. //一次快排(划分)
  5. static int partition(int parts[],int low, int high);
  6. //快排
  7. static void quick_sort(int parts[],int low, int high);
  8. public:
  9. //递增排序
  10. static void inc_sort(int keys[],int size);
  11. };
  12. int QuickSort :: partition(int parts[], int low, int high){
  13. int pivotkey=parts[low]; //将第一个元素作为枢轴
  14. while(low
  15. while(low=pivotkey) --high; //将比枢轴小的关键字记录移动到低端
  16. parts[low]=parts[high];
  17. while(low
  18. parts[high]=parts[low];
  19. }
  20. parts[low]=pivotkey;
  21. return low; //返回枢轴的位置
  22. }
  23. void QuickSort :: quick_sort(int parts[],int low,int high){
  24. if(low
  25. int pivotloc=QuickSort::partition(parts,low,high);
  26. QuickSort::quick_sort(parts,low,pivotloc-1);
  27. QuickSort::quick_sort(parts,pivotloc+1,high);
  28. }
  29. }
  30. void QuickSort :: inc_sort(int keys[],int size){
  31. QuickSort::quick_sort(keys,0,size-1);
  32. for(int k=0;k
  33. cout<
  34. cout<
  35. }
  36. void main(){
  37. int raw[]={49,38,65,97,76,13,27,49};
  38. int size=sizeof(raw)/sizeof(int);
  39. QuickSort::inc_sort(raw,size);
  40. }
#includeclass QuickSort{private://一次快排(划分)static int partition(int parts[],int low, int high);//快排static void quick_sort(int parts[],int low, int high);public://递增排序static void inc_sort(int keys[],int size);};int QuickSort :: partition(int parts[], int low, int high){int pivotkey=parts[low];//将第一个元素作为枢轴while(low=pivotkey) --high; //将比枢轴小的关键字记录移动到低端parts[low]=parts[high];while(low

C代码

  1. //快速排序非递归算法
  2. #include
  3. #include
  4. void quick_sort(int *pArr, int size){
  5. int * beginIdxs=(int *)malloc(size * sizeof(int)); //记录待调整子序列的首地址
  6. int * endIdxs=(int *)malloc(size * sizeof(int));//记录待调整子序列的尾地址
  7. beginIdxs[0]=0;
  8. endIdxs[0]=size-1;
  9. int curIdx=0;
  10. while(curIdx>-1){
  11. int low=beginIdxs[curIdx];
  12. int high=endIdxs[curIdx];
  13. int pivotkey=pArr[low]; //将第一个元素作为枢轴
  14. while(low
  15. while(low
  16. pArr[low]=pArr[high];
  17. while(low=pArr[low]) ++low;
  18. pArr[high]=pArr[low];
  19. }
  20. pArr[low]=pivotkey;
  21. int pivotidx=low;
  22. int begin=beginIdxs[curIdx];
  23. int end=endIdxs[curIdx];
  24. curIdx--;
  25. if(begin
  26. beginIdxs[++curIdx]=begin;
  27. endIdxs[curIdx]=pivotidx-1;
  28. }
  29. if(end>pivotidx+1){
  30. beginIdxs[++curIdx]=pivotidx+1;
  31. endIdxs[curIdx]=end;
  32. }
  33. }
  34. //打印结果
  35. for(int k=0;k
  36. cout<
  37. }
  38. }
  39. void main(){
  40. int raw[]={49,38,65,97,76,13,27,49};
  41. int size=sizeof(raw)/sizeof(int);
  42. quick_sort(raw,size);
  43. }
//快速排序非递归算法#include#includevoid quick_sort(int *pArr, int size){int * beginIdxs=(int *)malloc(size * sizeof(int)); //记录待调整子序列的首地址int * endIdxs=(int *)malloc(size * sizeof(int));//记录待调整子序列的尾地址beginIdxs[0]=0;endIdxs[0]=size-1;int curIdx=0;while(curIdx>-1){int low=beginIdxs[curIdx];int high=endIdxs[curIdx];int pivotkey=pArr[low]; //将第一个元素作为枢轴  while(low=pArr[low]) ++low;pArr[high]=pArr[low];}pArr[low]=pivotkey;int pivotidx=low;int begin=beginIdxs[curIdx];int end=endIdxs[curIdx];curIdx--;if(beginpivotidx+1){beginIdxs[++curIdx]=pivotidx+1;endIdxs[curIdx]=end;}}//打印结果for(int k=0;k

快速排序的平均时间复杂度为O(N*logN)。但快速排序在待排关键字序列有序或基本有序的情况下,快速排序将蜕化成起泡排序,其时间复杂度降为O(N^2) 。 经验证明,在所有O(N*logN)级的此类排序算法中,快速排序是目前被认为最好的一种内部排序方法。但是快排需要一个栈空间来实现递归。若每一趟划分都能够均匀的分割成长度相接近的两个子序列,则栈的最大深度为[logN]+1。因此空间复杂度为O(logN)。快排也是不稳定的。

快速排序有一个最坏的可能性,因此也就有很多优化来改进这个算法。

随机化快排:快速排序的最坏情况基于每次划分对主元的选择。基本的快速排序选取 第一个元素作为主元。这样在数组已经有序的情况下,每次划分将得到最坏的结果。一种比较 常见的优化方法是随机化算法,即随机选取一个元素作为主元。这种情 况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。一位前辈做出了一个精辟的总结:“随机化快速排序可 以满足一个人一辈子的人品需求。”
  随机化快速排序的唯一缺点在于,一旦输入数据中有很多的相同数据,随机化的效果将直 接减弱。对 于极限情况,即对于n个相同的数排序,随机化快速排序的时间复杂度将毫无疑问的降低到O(n^2)。解决方法是用一种方法进行扫描,使没有交换的情况下主 元保留在原位置。

平衡快排(Balanced Quicksort):每次尽可能地选择一个能够 代表中值的元素作为关键数据,然后遵循普通快排的原则进行比较、替换和递归。通常来说, 选择这个数据的方法是取开头、结尾、中间3个数据,通过比较选出其 中的中值。取这3个值的好处是在实际问题(例如信息学竞赛……)中,出现近似顺序数据或逆序数据的概率较大,此时中间数据必然成为中值,而也是事实上的近 似中值。万一遇到正好中间大两边小(或反之)的数据,取的值都接近最值,那么由于至少能将两部分分开,实际效率也会有2倍左右的增加,而且利于将数据略微 打乱,破坏退化的结构。

对于快排优化的问题可以看看Java API(JDK)中的例子,参见《java.util.Arrays的排序研究》