考研數據結構排序整理

                                        排序

刷完一遍王道後,發現差不多又忘記了。所以打算用一個月時間整理一下。先整理每一章的知識框架,然後時間充裕的話把書上的算法整理,主要以南郵數據結構的考試大綱爲主體,王道數據結構和陳慧南的數據結構(只作爲補充內容,看了排序的一部分,覺得不是很好耶)爲輔。

整理了五天(其實每天都是抽出一點時間,畢竟考研黨要學很多,哭泣。。。)
在這裏插入圖片描述

這個是網上搜的圖,懶得打表格了,其實框架裏面也有,哈哈哈哈
在這裏插入圖片描述

下面是王道和陳慧南數據結構書上的算法

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

小結哈哈哈
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章