排序
刷完一遍王道后,发现差不多又忘记了。所以打算用一个月时间整理一下。先整理每一章的知识框架,然后时间充裕的话把书上的算法整理,主要以南邮数据结构的考试大纲为主体,王道数据结构和陈慧南的数据结构(只作为补充内容,看了排序的一部分,觉得不是很好耶)为辅。
整理了五天(其实每天都是抽出一点时间,毕竟考研党要学很多,哭泣。。。)
这个是网上搜的图,懒得打表格了,其实框架里面也有,哈哈哈哈
下面是王道和陈慧南数据结构书上的算法
1.排序使用的顺序表和链表结构
(针对陈慧南那本教材)
//排序使用的顺序表和链表结构
typedef int T;
typedef struct list{
int Size,MaxList;
T Elements[MaxSize];
}Lists;
typedef struct node{
T Element;
struct node *Link;
}Node;
typedef struct list{
Node *First;
int Size;
}List;
2.直接插入排序
//顺序表的直接插入排序
void InsertSort(List *lst)
{
int i,j;
T x;
for(i=1;i<lst->Size;i++) //执行n-1趟
{
x=lst->Elements[i];//待插入元素存入临时变量
for(j=i-1;j>=0 && x<lst->Elements[j];j--) //从后往前查找插入位置
lst->Elements[j+1]=lst->Elements[j];//元素后移,j指针前移
lst->Elements[j+1]=x;//待插入元素找到的插入位置
}
}
//单链表的直接插入排序算法
void InsertSort(List *lst)
{
Node *unsorted,*sorted,*p,*q;
//p表示表中与待插入的记录比较的结点,q表示p的前驱结点
//sorted总是指向单链表中已经有序的部分子表的尾部,而指针unsotred指向sorted的后继结点,
//即待插入的记录结点
if(lst->First!=NULL) //空链表
{
sorted=lst->First;
while(sorted->Link!=NULL)
{
unsorted=sorted->Link; //至少一个结点
if(unsorted->Element<list->First->Element) //若待插入记录小于第一个记录
{
sorted->Link=unsorted->Link;//将待记录从链表取下
unsorted->Link=lst->First;//将待插记录插在链表的最前面
lst->First=unsorted;
}
else //若待插记录大于等于第一个记录
{
q=lst->First;p=q->Link;
while(unsorted->Element>p->Element)//搜索待插记录的适当插入位置
q=p;p=p->Link;
}
if(unsorted==p) sorted=unsorted;//将待插记录在有序子表末尾
else //将待插记录插在结点*q之后
{
sorted->Link=unsorted->Link;
unsorted->Link=p;q->Link=unsorted;
}
}
}
}
}
//直接插入排序(王道)
void InsertSort(Elementype A[],int n)
{
int i,j;
for(i=2;i<=n;i++) //依次将A[2]~A[n]插入到前面已排序序列
if(A[i].key<A[i-1].key) //若A[i]的关键码小于其前驱,需将A[i]插入有序表
{
A[O]=A[i];//复制为哨兵,A[0]不存放元素
for(j=i-1;A[O].key<A[j].key;--j) //从后往前查找待插入位置
A[j+1]=A[j];
A[j+1]=A[0];//复制到插入位置
}
}
3.希尔排序
//希尔排序
void InsSort(List *lst,int h)
{
int i,j;T x;
for(i=h;i<lst->Size;i+=h)
{
x=lst->Elements[i];
for(j=i-h;j>=0 && x<lst->Elements[j];j-=h)//位置j的同组前一个位置为j-h
lst->Elements[j+h]=lst->Elements[j];
lst->Elements[j+h]=x;
}
void ShellSort(List *lst)
{
int i,incr=lst->Size;
do{
incr=incr/3+1;
for(i=0;i<incr;i++) InsSort(lst,incr);//计算增量
}while(incr>1);
}
}
//希尔排序(王道)
void ShellSort(ElementType A[],int n)
{
//前后记录位置的增量是dk,不是1
//A[0]只是存储单元,不是哨兵,当j<=0时,插入位置已到
for(dk=n/2;dk>=1;dk=dk/2)//初始增量为总长度的一半,之后依次除2且向下取整
for(i=dk+1;i<=n;i++)
if(A[i].key<A[i-dk].key)
{
//需将A[i]插入有序增量子表
A[O]=A[i];//暂存在A[0]
for(j=i-dk;j>0 && A[0].key<A[j].key;j-=dk)
//待插入关键字之前以dk为增量的关键字只要比待插入关键字大的都往后移动dk位
A[j+dk]=A[0];//插入
}
}
4.折半插入排序(王道)
void InsertSort(ElemType A[],int n)
{
int i,j,low,high,mid;
for(i=2;i<=n;i++) //依次将A[2]~A[n]插入前面的已排序序列
{
A[0]=A[i];//将A[i]暂存到A[0]中
low=1;high=i-1;//设置折半查找的范围
while(low<=high)//折半查找(默认递增有序)
{
mid=(low+high)/2;//取中间值
if(A[mid].key>A[0].key) high=mid-1;//查找左半子表
else low=mid+1;//查找右半子表
}
for(j=i-1;j>=high+1;--j)
A[j+1]=A[j];//统一后移元素,空出插入位置
A[high+1]=A[0];//插入操作
}
}
5.冒泡排序
//冒泡排序(王道)
void BubbleSort(ElemType A[],int n)
{
//用冒泡排序法将序列中的元素按从小到大排列
for(int i=0;i<n-1;i++)
{
flag=false;//表示本趟冒泡是否发生交换的标志
for(j=n-1;j>i;j--)//一趟冒泡过程
if(A[j-1].key>A[j].key)
{
//若为逆序
swap(A[j-1],A[j]);//交换
flag=true;
}
if(flag==false)
return;//本趟遍历后没有发生交换,说明表已经有序
}
}
6.快速排序
//快速排序(王道)
void QuickSort(ElemType A[],int low,int high)
{
if(low<high) // 递归跳出的条件
{
//Partion()是划分操作,将表划分为满足上述条件的两个子表
int pivotpos=Partition(A,low,high);//划分
QuickSort(A,low,pivotpos-1);//依次对两个子表进行递归排序
QuickSort(A,pivotpos+1,high);
}
}
//分治,假设每次总以当前表中第一个元素作为枢轴值(基准)来对表进行划分,
//则必须将表中比枢轴大的元素向右移动,将比枢轴小的元素向左移动,使得一趟
//Partition()操作后,表中的元素被枢轴一分为二。
int Partition(ElemType A[],int low,int high)
{
ElemType pivot=A[low];//将当前表中第一个元素设为枢轴值,且对表进行划分
while(low<high){
//循环跳出条件
while(low<high && A[high]>=pivot) --high;
A[low]=A[high];//将比枢轴值小的元素移动到左端
while(low<high && A[low]<=pivot) ++low;
A[high]=A[low];//将比枢轴值大的元素移动到右端
}
A[low]=pivot;//枢轴元素存放到最终位置
return low;
}
7.简单选择排序
//简单选择排序(王道)
void SelectSort(ElemType A[],int n)
{
//对表A做简单选择排序,A[]从0开始存放元素
for(i=0;i<n-1;i++)//一共进行n-1趟
{
min=j; //记录最小元素位置
for(j=i+1;j<n;j++) //在A[i...n-1]中选择最小的元素
if(A[j]<A[min]) min=j;//更新最小元素位置
if(min!=i) swap(A[i],A[min]);//与第i个位置交换
}
}
8.堆排序
//堆排序 (王道)
//建立大根堆(自下往上逐步调整为大根堆
void BuildMaxHeap(ElemType A[],int len)
{
for(int i=len/2;i>0;i--)//从i=[n/2]~1,反复调整
AdjustDown(A,i,len);
}
void AdjustDown(ElemType A[],int k,int len)
{
//函数AdjustDown将元素k向下进行调整
A[0]=A[k] ;//A[0]暂存
for(i=2*k;i<=len;i*=2){
//沿key较大的子结点向下筛选
if(i<len && A[i]<A[i+1])//如果右孩子大一些,就只要考虑和右孩子比较
i++;
if(A[0]>=A[i]) break;//筛选结束,如果这个元素结点值不小于它的结点值,则不需要交换
else{
A[k]=A[i];//将A[i]调整到双亲结点上
k=i;//修改k值,以便继续向下筛选
}
}
A[k]=A[0];//将筛选结点的值放入最终的位置
}
//向上调整堆
void AdjustUp(ElemType A[],int n)
{
//参数k为向上调整的结点,也为堆的元素个数
A[0]=A[k];
int i=k/2;//若结点值大于双亲结点,则将双亲结点向下调,并继续向上比较
while(i>0 && A[i]<A[0])//跳出循环
{
A[k]=A[i];//双亲结点下调
k=i;
i=k/2;//继续向上比较
}
A[k]=A[0];//复制到最终位置
}
//堆排序算法
void HeapSort(ElemType A[],int len)
{
BuildMaxHeap(A,len);//初始建堆
for(i=len;i>1;i--)
{
//n-1趟的交换和建堆过程
Swap(A[i],A[1]);//输出堆顶元素(和堆底元素交换)
AdjustDown(A,1,i-1);//整理,再把剩余的i-1个元素整理成堆
}
}
9.归并排序
//归并排序(王道)
ElemType *B(ElemType *)malloc(n+1)*sizeof(ElemType);//辅助数组B
void Merge(ElemType A[],int low,int mid,int high){
//表A的两段A[low...mid]和A[mid+1...high]
for(int k=low;k<=high;k++)
B[k]=A[k];//将A中所有元素复制到B中
for(i=low;j=mid+1,k=i;i<=mid && j<=high;j++) {
if(B[i]<=B[j])//比较B的左右两段中的元素
A[k]=B[i++];//将较小值复制到A中
else
A[k]=B[j++];
}
while(i<=mid) A[k++]=B[i++];//若第一个表未检测完,复制
while(j<=high) A[k++]=B[j++];//若第二个表未检测完,复制
}
//合并
void MergeSort(ElemType A[],int low,int high)
{
if(low<high){
int mid=(low+high)/2;//从中间划分两个子序列
MergeSort(A,low,mid);//对左侧子序列进行递归排序
MergeSort(A,mid+1,high);//对右侧子序列进行递归排序
Merge(A,low,mid,high);//归并
}
}
//链表上的合并排序
//1.合并函数
Node *Merge(Node *p,Node *q)
{
Node *rear,head;//head为哑结点,rear为指针变量
rear=&head;//rear指向head结点
while(p!=NULL && q!=NULL)
{
//合并两个有序链表
if(p->Element<=q->Element)
{
rear->Link=p;rear=p;
p=p->Link;
}
else
{
rear->Link=q;rear=q;
q=q->Link;
}
}
if(p==NULL) rear->Link=q;//将一个链表的剩余部分链至结果链表的尾部
else rear->Link=p;
return head.Link;//返回结果链表的起始结点地址
}
//2.分割函数,将一个链表分割成两个长度基本相等的链表
//pos指针和mid开始向后移动,pos每次向后移动两个结点,mid每次向后一定一个结点。
//等到pos移出最后一个结点成为空指针,以mid指示的结点作为前半部分子表的表尾。
//函数值最后返回后半结点表的头指针
Node *Divide(Node *p)
{
Node *pos,*mid,*q;
if(mid=p)==NULL) return NULL;
pos=mid->Link;
while(pos!=NULL)
{
pos=pos->Link;
if(pos!=NULL)
{
mid=mid->Link;pos=pos->Link;
}
}
q=mid->Link;mid->Link=NULL;
return q;
}
//3.两路合并排序
//首先调用函数Divide对链表对半分割成前后两个子链表。分别对这两个子链表实行合并排序。
//也就是进行两次递归调用,将这两个子链表分别排序成有序表。
//最后,调用Merge函数将这两个有序子链表合并成一个有序链表,从而结束合并排序。
void RMSort(Node** sublst)
{
if(*sublst!=NULL && (*sublst)->Link!=NULL)
{
Node *second=Divide(*sublst);
RMSort(sublst);
RMSort(&second);
*sublst=Merge(*sublst,second);
}
}
void RMergeSort(List *lst)
{
RMSort(&lst->First);
}
小结哈哈哈