数据结构---排序

                                        排序

刷完一遍王道后,发现差不多又忘记了。所以打算用一个月时间整理一下。先整理每一章的知识框架,然后时间充裕的话把书上的算法整理,主要以南邮数据结构的考试大纲为主体,王道数据结构和陈慧南的数据结构(只作为补充内容,看了排序的一部分,觉得不是很好耶)为辅。

整理了五天(其实每天都是抽出一点时间,毕竟考研党要学很多,哭泣。。。)
在这里插入图片描述

这个是网上搜的图,懒得打表格了,其实框架里面也有,哈哈哈哈
在这里插入图片描述

下面是王道和陈慧南数据结构书上的算法

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);
 } 
 
 

小结哈哈哈
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值