排序算法总结

下面简要总结了常用的一些排序算法。如有错误,还请大家指正、见谅~~谢谢~~

【1】插入排序:

是一个对少量元素进行排序的有效算法。实现比较简单。时间复杂度:O(n^2),空间复杂度:O(1)。是稳定的排序方法。

代码:

//insertion sort #include <iostream> using namespace std; //insertion sort void InsertionSort(int *a,int n) { int temp; for(int i = 1;i < n;++i) { temp = *(a + i); int j = i - 1; while(j >= 0 && *(a + j) > temp) { *(a + j + 1) = *(a + j); --j; } *(a + j + 1) = temp; } } int main() { int n,temp; cout<<"please input the number of the values that need to sort:"<<endl; cin>>n; int *a = (int*)malloc(n * sizeof(int)); cout<<"please input each value:"<<endl; for(int i = 0;i < n;++i) { cin>>temp; *(a + i) = temp; } /* //insertion sort for(int i = 1;i < n;++i) { temp = *(a + i); int j = i - 1; while(j >= 0 && *(a + j) > temp) { *(a + j + 1) = *(a + j); --j; } *(a + j + 1) = temp; }*/ InsertionSort(a,n); cout<<"the values after sort:"<<endl; for(int i = 0;i < n;++i) cout<<*(a + i)<<" "; free(a);}

数据测试:


上述代码可以改进的一个地方是:在查找插入位置的时候可以采用二分查找,但是这样依然不可以把时间复杂度降低为O(nlogn),因为移动元素的复杂度没有降低。所以时间复杂度仍然是O(n^2)。

做此改进需要添加函数InsertLoc用于二分查找需要插入的位置,以及修改函数InsertionSort的实现。具体如下:

//改进:用二分查找来找到插入的位置 //在数组a[low]---a[high]查找val插入的位置 int InsertLoc(int *a,int low,int high,int val) { if(low == high) { if(val > *(a + low))return (low + 1); else return low; } int mid = (low + high) / 2; if(val > *(a + mid) && val > *(a + mid + 1)) return InsertLoc(a,mid + 1,high,val); else if(val < *(a + mid) && val < *(a + mid + 1)) return InsertLoc(a,low,mid,val); else return mid; } void InsertionSort(int *a,int n) { int temp,insert_location; for(int i = 1;i < n;++i) { temp = *(a + i); int j = i - 1; insert_location = InsertLoc(a,0,j,temp); cout<<"insert_location:"<<insert_location<<endl; while(j >= insert_location) { *(a + j + 1) = *(a + j); --j; } *(a + insert_location) = temp; for(int m = 0;m <= i;++m) cout<<*(a + m)<<" "; cout<<endl; } }

【2】选择排序

第一次找出A[0,...,n-1]的最小的元素,与A[0]交换,接着,找出A[1,...,n-1]的次小得元素,与A[1]互换。对A中头n-1个元素执行这一过程。时间复杂度:O(n^2),空间复杂度O(1)。是不稳定的排序方法。比如序列5 8 5 2 9,第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序是不稳定的排序算法。

但是严蔚敏的《数据结构》书上面Page289页说,所有时间复杂度为O(n^2)的简单排序都是稳定的。不知道为什么?求指导~~

其给出的简单排序的伪代码:

void SelectSort(SqList &L) { //对顺序表L做简单排序 for(i = 1;i < L.length;++i)//选择第i小得记录,并交换到位 { j = SelectMinKey(L,i);//在L.r[i..L.length]中选择key最小的记录 if(i != j)//与第i个记录交换 { temp = L.r[i]; L.r[i] = L.r[j]; L.r[j] = temp; } } }

 

代码:

//选择排序 #include <iostream> using namespace std; void ChoseSort(int* a,int n) { int temp,minVal,minIndex; for(int i = 0;i < n - 1;++i) { minVal = *(a + i);//记录a[i,...,n-1]之间的最小值 minIndex = i;//记录a[i,...,n-1]之间的最小值的下标 for(int j = i + 1;j < n;++j) { if(minVal > *(a + j)) { minVal = *(a + j); minIndex = j; } } //交换a[i]和a[i,...,n-1]之间的最小值最小值 if(minIndex != i) { temp = *(a + i); *(a + i) = *(a + minIndex); *(a + minIndex) = temp; } } } int main() { int n,temp; cout<<"please input the number of the values that need to sort:"<<endl; cin>>n; int *a = (int*)malloc(n * sizeof(int)); cout<<"please input each value:"<<endl; for(int i = 0;i < n;++i) { cin>>temp; *(a + i) = temp; } ChoseSort(a,n); cout<<"the values after sort:"<<endl; for(int i = 0;i < n;++i) cout<<*(a + i)<<" "; free(a); }

【3】合并排序

采用分治法。将n个元素分成各含n/2个元素的子序列,用合并排序法对两个子序列递归的排序(子序列长度为1时递归结束),最后合并两个已排序的子序列得到结果。时间复杂度:O(nlogn),空间复杂度:O(n)。是稳定的排序方法。

代码:

//合并排序 #include <iostream> using namespace std; #define MAX_VALUE 100000//用于设置哨兵,避免检查是否每一个堆都是空的 //合并两个子数组的函数 void Merge(int *a,int p,int q,int r) { int num1,num2; num1 = q - p + 1; num2 = r - q; int *a1 = (int*)malloc((num1 + 1) * sizeof(int)); int *a2 = (int*)malloc((num2 + 1) * sizeof(int)); for(int i = 0;i < num1;++i) *(a1 + i) = *(a + p + i); *(a1 + num1) = MAX_VALUE;//设置哨兵元素 for(int i = 0;i < num2;++i) *(a2 + i) = *(a + q + 1 + i); *(a2 + num2) = MAX_VALUE;//设置哨兵元素 //进行排序 int index1 = 0; int index2 = 0; for(int i = p;i <= r;++i) { if(*(a1 + index1) < *(a2 + index2)) { *(a + i) = *(a1 + index1); ++index1; } else { *(a + i) = *(a2 + index2); ++index2; } } free(a1); free(a2);}//递归合并排序算法 void MergeSort(int *a,int p,int r) { if(p < r) { int q = (p + r) / 2; MergeSort(a,p,q); MergeSort(a,q + 1,r); Merge(a,p,q,r); } } int main() { int n,temp; cout<<"please input the number of the values that need to sort:"<<endl; cin>>n; int *a = (int*)malloc(n * sizeof(int)); cout<<"please input each value:"<<endl; for(int i = 0;i < n;++i) { cin>>temp; *(a + i) = temp; } MergeSort(a,0,n - 1); cout<<"the values after sort:"<<endl; for(int i = 0;i < n;++i) cout<<*(a + i)<<" "; free(a);}

如果不使用哨兵元素,需要修改Merge函数,如下:

//合并两个子数组的函数(不使用哨兵元素) void Merge(int *a,int p,int q,int r) { int num1,num2; num1 = q - p + 1; num2 = r - q; int *a1 = (int*)malloc(num1 * sizeof(int)); int *a2 = (int*)malloc(num2 * sizeof(int)); for(int i = 0;i < num1;++i) *(a1 + i) = *(a + p + i); for(int i = 0;i < num2;++i) *(a2 + i) = *(a + q + 1 + i); //进行排序 int index1 = 0; int index2 = 0; int index = p; while(index1 < num1 && index2 <num2) { if(*(a1 + index1) < *(a2 + index2)) { *(a + index) = *(a1 + index1); ++index; ++index1; } else{ *(a + index) = *(a2 + index2); ++index; ++index2; } } while(index1 < num1) { *(a + index) = *(a1 + index1); ++index; ++index1; } while(index2 < num2) { *(a + index) = *(a2 + index2); ++index; ++index2; } free(a1);
	free(a2);
 }
 

【4】冒泡排序

每一趟都比较相邻两个元素,若是逆序的,则交换。结束的条件应该是“在一趟排序过程中没有进行过交换元素的操作”。时间复杂度:O(n^2),空间复杂度O(1)。是稳定的排序。

#include <iostream> using namespace std; void BubbleSort(int *a,int n) { int flag,temp;//标记是否进行过交换操作 for(int i = 0;i < n - 1;++i) { flag = 0; for(int j = 0;j < n - 1 - i;++j) { if(*(a + j) > *(a + j + 1)) { temp = *(a + j); *(a + j) = *(a + j + 1); *(a + j + 1) = temp; flag = 1; } } if(flag == 0)break; } } int main() { int n,temp; cout<<"please input the number of the values that need to sort:"<<endl; cin>>n; int *a = (int*)malloc(n * sizeof(int)); cout<<"please input each value:"<<endl; for(int i = 0;i < n;++i) { cin>>temp; *(a + i) = temp; } BubbleSort(a,n); cout<<"the values after sort:"<<endl; for(int i = 0;i < n;++i) cout<<*(a + i)<<" ";
	free(a);
 }
 

【5】快速排序

它是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序元素分成两个部分,其中一部分元素比另一部分元素小。再分别对这两部分元素进行排序。以达到整个元素序列有序。时间复杂度:O(nlogn),空间复杂度O(logn),是不稳定的算法。

代码:

#include <iostream> using namespace std; int Partition(int *a,int low,int high) { int PivotKey = *(a + low);//用第一个元素做枢轴 while(low < high) { while(low < high && *(a + high) > PivotKey)--high; *(a + low) = *(a + high); while(low < high && *(a + low) < PivotKey)++low; *(a + high) = *(a + low); } *(a + low) = PivotKey; return low; } void QuickSort(int *a,int low,int high) { if(low < high) { int PivotLoc = Partition(a,low,high); QuickSort(a,low,PivotLoc - 1); QuickSort(a,PivotLoc + 1,high); } } int main() { int n,temp; cout<<"please input the number of the values that need to sort:"<<endl; cin>>n; int *a = (int*)malloc(n * sizeof(int)); cout<<"please input each value:"<<endl; for(int i = 0;i < n;++i) { cin>>temp; *(a + i) = temp; } QuickSort(a,0,n - 1); cout<<"the values after sort:"<<endl; for(int i = 0;i < n;++i) cout<<*(a + i)<<" "; free(a);}


 

一些好的参考资料:不同排序算法间的比较:http://commons.wikimedia.org/wiki/File:SortingAlgoComp.png
一些排序算法的 C 及 Pascal 实现 :
http://www.nocow.cn/index.php/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95

最后,简要比较一下各排序算法,转自维基百科:

简要比较

名称数据对象稳定性时间复杂度空间复杂度描述
平均最坏
插入排序数组、链表O(n2)O(1)(有序区,无序区)。把无序区的第一个元素插入到有序区的合适的位置。对数组:比较得少,换得多。
直接选择排序数组×O(n2)O(1)(有序区,无序区)。在无序区里找一个最小的元素跟在有序区的后面。 对数组:比较得多,换得少。
链表
堆排序数组×O(nlogn)O(1)(最大堆,有序区)。从堆顶把根卸出来放在有序区之前,再恢复堆。
归并排序数组、链表O(nlogn)O(n) +O(logn) , 如果不是从下到上把数据分为两段,从两段中逐个选最小的元素移入新数据段的末尾。可从上到下或从下到上进行。
快速排序数组×O(nlogn)O(n2)O(logn) ,O(n)(小数,枢纽元,大数)。
Accum qsort链表O(nlogn)O(n2)O(logn) ,O(n)(无序区,有序区)。把无序区分为(小数,枢纽元,大数),从后到前压入有序区。
  
决策树排序 O(logn!)O(n!)O(n) <O(logn!) <O(nlogn)
  
计数排序数组、链表O(n)O(n+m)统计小于等于该元素值的元素的个数 i,于是该元素就放在目标数组的索引 i位。(i≥0)
桶排序数组、链表O(n)O(m)将值为 i 的元素放入i 号桶,最后依次把桶里的元素倒出来。
基数排序数组、链表  一种多关键字的排序算法,可用桶排序实现。
  • 均按从小到大排列
  • n 代表数据规模
  • m 代表数据的最大值减最小值
 
 
 
 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/xiajun/archive/2011/10/23/2298642.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值