以下算法都编译通过,具体原理相信大家都懂,直接上代码。
内部排序方法
外部排序方法
插入排序
1.直接插入排序
typedef int eleType; typedef struct{ eleType key[MAXSIZE], int length; }listSeq; void InsertSort(listSeq &L) { int j; for (int i=1;i<=L.length;i++) { L.key[0]=L.key[i]; j=i-1; while((L.key[0]<L.key[j])&&j>0) { L.key[j+1]=L.key[j]; j--; } L.key[j+1]=L.key[0]; } }
复杂度分析:
插入排序在最好的情况下(序列已经排好)有最少的比较次数 ,但是它在元素移动方面效率非常低下,最糟糕的情况下是逆序(比较次数达到(n+2)(n-1)/2,移动次数为 (n+4)(n-1)/2,因此时间复杂度为O(n2),附加存储空间为O(1))因为它只与毗邻的元素进行比较,效率比较低。
2.希尔排序算法
void shellInsert(listSeq &L,int d) { int temp,j; for (int i=d;i<L.length;i++) //理解这句话 { temp=L.key[i]; j=i-d; while (temp<L.key[j]&&j>=0) { L.key[j+d]=L.key[j]; j-=d; } L.key[j+d]=temp; } } void shellSort(listSeq &L) { int d; d=L.length/2; while (d>1) { shellInsert(L,d); //这个地方不需用引用 d=d/2; } }
复杂度分析:
希尔排序实际上是预处理阶段优化后的插入排序,一般而言,在 比较大时,希尔排序要明显优于插入排序。
希尔排序的时间耗费与索取的“增量”序列的函数有关,到目前为止,尚未有人求出一个最好的增量序列是希尔时间性能达到最好。经过大量研究,普遍认为希尔的时间复杂度为O(n3/2)。空间上只需要一个元素辅助空间。
交换排序
1.冒泡排序
每一轮选一个最大的元素。
void bubbleSort(listSeq &L) { int temp; int flag=1; for (int i=0;i<(L.length-1)&&flag;i++) //当不改变的时候就终止! { flag=0; for (int j=0;j<L.length-i-1;j++) { if (L.key[j+1]<L.key[j]) { temp=L.key[j]; L.key[j]=L.key[j+1]; L.key[j+1]=temp; flag=1; } } } }
复杂度分析:
冒泡排序在最优情况下只需要经过n-1次比较即可得出结果(即对于完全正序的表,此时循环一次就达到了终止条件),最坏情况下也要进行 次比较。也就是O(n2)
附加存储空间为O(1)。
2.快排 --冒泡排序的改进
采用递归的方式
int partQuickSort(listSeq &L,int left,int right) //注意返回中间值 { int temp; int low=left,high=right; temp=L.key[low]; while (low<high) { while((L.key[high]>=temp)&&low<high) high--; L.key[low]=L.key[high]; //此时high被悬空 while((L.key[low]<temp)&&low<high) low++; L.key[high]=L.key[low]; //此时low被悬空 } L.key[low]=temp; //这个不要忘记了; return low; } void QuickSort(listSeq &L,int low,int high) { int mid; if (low<high) { mid=partQuickSort(L,low,high); QuickSort(L,low,mid-1); QuickSort(L,mid+1,high); } }
复杂度分析:
快速排序采用的“大事化小,小事化了”的思想,用递归的方法,将原问题分解成若干规模较小但与原问题相似的子问题进行求解。快速算法的平均时间复杂度为O(nlogn) ,平均而言,快速排序是基于关键字比较的内部排序算法中速度最快者;但是由于快速排序采用的是递归的方法,因此当序列的长度比较大时,对系统栈占用会比较多。快速算法尤其适用于随机序列的排序。
最坏情况,当序列为正序的时候,要进行 次排序。理想情况下每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n 趟划分,便可以得到理想长度为1的子表。整个算法时间复杂度为O(nlog2n)(因为每次划分就要进行n次比较)。
空间复杂度上,尽管快排只需要一个元素的辅助空间,但快排需要一个栈空间来实现递归。最坏情况下,栈的最大深度为n。总得评卷时间复杂度为O(log2n)。
归并排序
//将有二个有序数列a[first...mid]和a[mid...last]合并。 void mergearray(int a[], int first, int mid, int last, int temp[]) { int i = first, j = mid + 1; int m = mid, n = last; int k = 0; while (i <= m && j <= n) { if (a[i] <= a[j]) temp[k++] = a[i++]; else temp[k++] = a[j++]; } while (i <= m) temp[k++] = a[i++]; while (j <= n) temp[k++] = a[j++]; for (i = 0; i < k; i++) a[first + i] = temp[i]; } void mergesort(int a[], int first, int last, int temp[]) { if (first < last) { int mid = (first + last) / 2; mergesort(a, first, mid, temp); //左边有序 mergesort(a, mid + 1, last, temp); //右边有序 mergearray(a, first, mid, last, temp); //再将二个有序数列合并 } } void MergeSort(int a[], int n) { int *p = new int[n]; //temp mergesort(a, 0, n - 1, p); delete[] p; } int main(int argc, char* argv[]) { int a[10]; int t; cout<<"请输入长度:"<<endl; cin>>t; cout<<"请输入数组:"<<endl; for (int i=0;i<t;i++) cin>>a[i]; MergeSort(a,t); for (int j=0;j<t;j++) cout<<a[j]<<" "; cout<<endl; return 0; }
复杂度分析:
对长度为n的数据表进行排序,必须要进行log2n趟排序,每一趟归并军队数据表中的n个元素做一次操作,时间复杂度为O(n),总得时间复杂度为O(nlog2n)。
归并排序最大特点就是它是稳定的排序方法。通常情况下实验归并排序需要与待排序数据表等大小的辅助空间,所以空间复杂度为O(n)。