内部排序
插入排序
R[0]设置为哨兵
R[0]=R[i]
记录后移
R[j+1]=R[j]
插入
l[j+1]=l[0]
直接插入排序(顺序查找)
利用顺序查找实现在R[1…i-1]中查找R[i]的插入位置
void InsertionSort(int l[]){
int i, j;
for(i=2; i<l.length(); ++i)
if(l[i] < l[i-1]){
l[0] = l[i];//设置哨兵
for(j=i-1; l[0]<l[j]; --j)
l[j+1]=l[j];//记录后移
l[j+1]=l[0];//插到j的后面j+1的位置
}
}
折半插入排序(折半查找)
利用折半查找实现在R[1…i-1]中查找R[i]的插入位置
void BilnsertionSort(int l[]){
int i,j;
for(i=2; i<l.length(); ++i){
l[0]=l[i];//哨兵
int low=1,high=i-1;
while(low<=high){//折半
int m=(low+high)/2;
if(l[0]<l[m])
high=m-1;
else
low=m+1;
}
for(j=i-1; j>=low; --j)//记录后移
l[j+1]=l[[j];
l[low]=l[0];//插入
}
}
希尔排序(逐趟缩小增量)
待排序列先做宏观调整,再做微观调整
宏观调整:跳跃式插入排序
其中d为增量,它的值在排序过程中逐渐减小,直到最后一次减为1
void ShellInsert(int l[],int dk){//对顺序表做一趟希尔排序,dk为增量
int j;
for(int i=1+dk; i<l.length(); ++i)
if(l[i]<l[i-dk]){
l[0]=l[i];//哨兵
for(j=i-dk; j>0 && (l[0]<l[j]); j-=dk)//加上j>0的条件是因为j无法等于0,导致比较时越界
l[j+dk]=l[j];//后移
l[j+dk]=l[0];//插入
}
}
void ShellInsert(int l[], int dlta[], int t){
//按照增量序列dlta[0..t-1]对l作希尔排序
for(int k=0; k<t; ++k){
ShellInsert(l,dlta[k]);//一趟增量为dlta[k]的插入排序
}
}
快速排序
起泡排序
void BubbleSort(int R[], int n){
int i=n;
while(i>1){
int lastExchangeIndex=1;
for(int j=1; j<i; ++j){
if(R[j]>R[j+1]){//相邻元素两两比较,根据大小关系决定是否交换
swap(R[j], R[j+1]);
lastExchangeIndex=j;
}
}
i=lastExchangeIndex;//更新i,lastExchangeIndex后的元素有序
}
}
快速排序
分治的思想
划分:将数组中的元素按照某个元素作为基准进行划分,使得,左边任意元素都小于右边任意元素
递归:左右两部分分别排序
合并:此时数组已经有序,不用合并
void quickSort(int R[], int l, int r){
if(l<r){
//划分
int i=l,j=r,x=s[l];
while(i<j){
while(i<j && s[j]>=x)//从右向左找第一个小于x的数的下标
j--;
if(i<j)
s[i++]=s[j];
while(i<j && s[i]<x)//从左向右找第一个大于等于x的数的下标
i++;
if(i<j)
s[j--]=s[i];
}
s[i]=x;
//递归求解
quickSort(s,l,i-1);
quickSort(s,i+1,r);
}
}
选择排序
简单选择排序
void SelectSort(int l[]){
for(int i=0; i<l.length()-1; ++i){
int count=i;
for(int j=i+1; j<l.length();++j){
if(l[j]<l[count])
count=j;
}
int temp=l[i];
l[i]=l[count];
l[count]=temp;
}
}
堆排序
int* HeapSort(MaxHeap &h){
BUildHeap(h);//建堆
int *res;
res=(int *)malloc(sizeof(int) * h->size)
for(int i=0; i<h->size; ++i){
res[i]=DeleteMax(h);
}
return res;
}
归并排序
分治思想
将两个或两个以上的有序子序列归并为一个有序序列(通常为2-路归并排序)
//将有二个有序数列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); //再将二个有序数列合并
}
}
bool MergeSort(int a[], int n)
{
int *p = new int[n];
if (p == NULL)
return false;
mergesort(a, 0, n - 1, p);
delete[] p;
return true;
}
基数排序
多关键字排序
借助多关键字排序的思想来实现单关键字排序
高位优先法(MSD):
先对K0进行排序
低位优先法(LSD):
先对Kn-1进行排序
链式基数排序
采用分配-收集的方法,不需要进行关键字的比较
各种排序方法的综合比较
时间性能
1 平均时间性能:
时间复杂度为O(logn):
快速排序,堆排序,归并排序
时间复杂度为O(n²):
直接插入排序,起泡排序,简单选择排序
时间复杂度为O(d(n+rd)):
基数排序
2 当待排记录顺序有序时:
直接插入排序,起泡排序 简化为O(n)
快速排序蜕化为O(n²)
3 简单选择排序,堆排序,归并排序的时间性能不随记录中关键字的分布而改变
空间性能
排序方法的稳定性