排序算法2
简单排序算法
公用部分
#define MAXSIZE 10
typedef struct {
int r[MAXSIZE+1];//r[0]用作哨兵或临时变量
int length;
}SqList;
void swap(SqList *L,int i,int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
堆排序
堆是具有下列性质的完全二叉树:
- 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆。
- 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将他移走,然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列。
void HaepSort(SqList *L)
{
int i;
//构造大顶堆
for(i=L->length/2;i>0;i--)/*序列从0到L->length/2,都是有孩子的结点*/
{
HeapAdjust(L,i,L->length);
}
//将堆顶元素和最后一个元素交换,得到有序序列
for(i=L->length;i>1;i++)
{
swap(L,1,i);
HeapAdjust(L,1,i-1);
}
}
void HeapAdjust(SqList *L,int s,int m)
{
int temp,j;
temp = L->r[s];
for(j=2*s;j<=m;j*=2)//找到左右子结点
{
if(j < m && L->r[j] < L->r[j+1])//找到相对较大的孩子结点
++j;
if(temp >= L->r[j])
break;
//交换值
L->r[s] = L->r[j];
s = j;
//若j*=2后小于等于m,则继续向下层执行
}
//交换值
L->r[s] = temp;
}
归并排序
假设初始序列有含有n个记录,则可以看成是n个有序序列的子序列,每个子序列的长度为1,然后两辆归并,得到[n/2]个长度为2或1的有序子序列;再两两归并…..,如此重复,直到得到一个长度为n的有序序列。
void MergeSort(SqList *L)
{
MSort(L->r,L->r,1,L->length);
}
void MSort(int SR[],int TR1[],int s,int t)
{
int m;
int TR2[MAXSIZE+1];
if(s==t)
{
TR1[s] = SR[s];
}
else
{
m = (s + t)/2;//划分序列
MSort(SR,TR2,s,m);//递归调用排序子序列
MSort(SR,TR2,m+1,t);//递归调用排序子序列
Merge(TR2,TR1,s,m,t);//合并子序列
}
}
void Merge(int SR[],int TR[],int i,int m,int n)
{
int j,k,l;
//把较小的插入TR中
for(j=m+1,k=i;i<=m && j<=n;k++)
{
if(SR[i] < SR[j])
TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
//若还有剩余的,则连续插入后端即可
if(i <= m)
{
for(l=0;l<=m-i;l++)
TR[k+l] = SR[i+l];
}
if(j<=n)
{
for(l=0;l<=n-j;l++)
TR[k+l] = SR[i+l];
}
}
非递归实现
void MergeSort2(SqList *L)
{
//申请额外的空间
int* TR = (int *)malloc(L->length * sizeof(int));
int k = 1;
while(k < L->length)
{
MergePass(L->r,TR,k,L->length);
k = k * 2;//子序列长度加倍
MergePass(TR,L->r,k,L->length);
k = k * 2;
}
}
void MergePass(int SR[],int TR[],int s,int n)
{
int i = 1;
int j;
while(i <= n- 2*s +1)
{
Merge(SR,TR,i,i+s-1,i- 2*s +1);
i = i + 2*s;
}
if(i < n-s+1)
Merge(SR,TR,i,i+s-1,n);
else
for(j=i;j<=n;j++)
TR[j] = SR[j];
}
快速排序
通过一趟排序将序列记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,最终得到有序序列。
void QuickSort(SqList *L)
{
QSort(L,1,L->length);
}
void QSort(SqList *L,int low,int high)
{
int pivot;
if(low < high)
{
//得到中间枢轴值的下标,将序列一份为二
pivot=Partition(L,low,high);
//对子序列递归排序
QSort(L,low,pivot-1);
QSort(L,pivot+1,high);
}
}
int Partition(SqList *L,int low,int high)
{
int pivotkey;
pivotkey = L->r[low];//选取枢轴
while(low < high)//当两个下标相遇时,排序完成,退出
{
//将大于枢轴的过滤掉
while(low<high && L->r[high] >= pivotkey)
high--;
//交换小的枢轴
swap(L,low,high);
//将小于枢轴的过滤掉
while(low < high && L->r[low] <= pivotkey)
low++;
//交换大的枢轴
swap(L,low,high);
}
return low;
}
优化
- 优化选取枢轴:三数取中,九数取中
- 优化不必要交换:将枢轴关键字备份,采用替换赋值,而不是交换的方式
- 当子序列比较小时,切换到直接插入排序
- 优化递归操作