排序算法

爲了招聘將以前學過的排序算法又複習了一遍,就貼了出來,希望對忙於找工作的同學有點幫助!同時也希望大家有什麼好的算法貼出來一起探討。
#include<stdio.h>
#define N 8
/*
直接插入排序是一種基本的插入排序方法,其基本操作是將第i個記錄插入到前面的i-1個已排好序的記錄中。
具體的過程爲:將第i個記錄的關鍵字Ki順次與前面記錄的關鍵字Ki-1 ,Ki-2,...,K1比較,將所有關鍵字大於Ki的
記錄一次向後移動一個位置,直到遇見一個關鍵字小於或等於Ki的記錄Kj,此時Kj後面必爲空位置,將第i個記錄插入
空位置即可。*/
void InsSort(int temp[],int length){
	//對記錄數組r做直接插入排序,length爲數組中待排序的記錄的數目
	int i=2;
	int j;
	for(;i<=length;i++){
		temp[0]=temp[i];j=i-1;//將待插入記錄放到監視哨temp[0]中
		while(temp[0]<temp[j]){
			temp[j+1]=temp[j];j=j-1;
		}
		temp[j+1]=temp[0];
	}
}
void print(int temp[],int length){
	int i=1;
	for(;i<=length;i++){
		printf("%d ",temp[i]);
	}
	printf("\n");
}
//折半排序
void BinSort(int r[],int length){
	//對記錄數組r進行折半插入排序,length爲數組長度
	int i=2;
	int j,low,high,mid,x;
	for(;i<=length;i++){
		x=r[i];
		low=1;high=i-1;
		while(low<=high){
			mid=(low+high)/2;
			if(x<r[mid]) high=mid-1;
			else low=mid+1;
		}
		for(j=i-1;j>=low;--j) r[j+1]=r[j];
		r[low]=x;
	}
}
/*
希爾排序:當子序列記錄間的間隔爲d時,共有d個子序列,需要對d個子序列分別進行插入排序。但是算法在具體實現時
並不是先對第一個子序列完成插入排序,再對另一個子序列進行插入排序,而是從第一個子序列的第二個記錄開始,順序掃描
整個待排序記錄序列,當前記錄屬於那個子序列,就在那個子序列中進行插入排序。
*/
void ShellInsert(int r[],int length,int delta){
	//對記錄數組r做一趟希爾插入排序,length爲數組的長度,delta爲增量
	int i,j;
	for(i=1+delta;i<=length;i++){//1+delta爲第一個子序列的第二個元素的下標
		if(r[i]<r[i-delta]){
			r[0]=r[i];//備份r[i]
			for(j=i-delta;j>0&&r[0]<r[j];j-=delta){
				r[j+delta]=r[j];
			}
			r[j+delta]=r[0];
		}
	}

}
void ShellSort(int r[],int length,int delta[],int n){
	//對記錄數組r作希爾排序,length 爲數組r的長度,delta爲增量數組,n爲delta[]的長度
	int i;
	for(i=0;i<n;i++){
		ShellInsert(r,length,delta[i]);
	}
}
//冒泡排序:反覆掃描待排序記錄序列,在掃描過程中順次比較相鄰的兩個元素的大小,
//若逆序就交換位置。每次將最大的元素放置到待排序列的最後。
void BubbleSort(int r[],int length){
	int i,j,temp;
	int change=1;//判斷元素是否有逆序
	for(i=1;i<=length-1&&change;++i){
		change=0;
		for(j=1;j<=length-i;++j){
			if(r[j]>r[j+1]){
				temp=r[j];
				r[j]=r[j+1];
				r[j+1]=temp;
				change=1;
			}
		}
	}
}
/*
快速排序:從待排序記錄序列中選取一個記錄爲(通常選取第一個記錄)樞紐,其關鍵字設爲k1,然後將其關鍵字小於K1的
記錄移到前面,而將關鍵字大於K1的記錄移到後面,結果將待排序記錄分成兩個子表,最後將關鍵字爲K1的記錄插入到其分界線的位置處
。我們將這個過程稱作一次快速排序。通過一次劃分後,就以關鍵字爲K1的記錄爲界,就將待排序列分成兩個兩個子表。且前面的子表中的所有記錄
的關鍵字均小於K1.而後面子表中所有記錄的關鍵字均不小於K1。對分割後的子表繼續按上述原則進行分割,知道所有子表的表長不超過1爲止,此時待排序記錄
序列就變成了一個有序表。
*/
int QKPass(int r[],int left,int right){
	//對記錄數組r中的人r[left]至r[right]部分進行一趟快速排序,並得到基準位置,使得排序後的結果滿足其之後(前)的記錄的關鍵字卻不小於(大於)基準記錄
	int x=r[left];
	int low=left,high=right;
	while(low<high){
		while(low<high&&r[high]>=x){
			high--;//high從右向左找小於x的記錄
		}
		if(low<high){
			r[low]=r[high];//找到小於x的記錄則進行交換
			low++;
		}
		while(low<high&&r[low]<x)//low從左向右找大於x的記錄
			low++;
		if(low<high){//找到大於x的記錄則進行交換
			r[high]=r[low];
			high--;
		}
	}
	r[low]=x;//將基準記錄保存到low=high的位置
	print(r,8);
	return low;//返回基準記錄的位置
}

	
void QKSort(int r[],int low,int high){
	//對記錄數組r[low..high]調用快速排序算法進行排序。
	int pos=0;
	if(low<high){
		pos=QKPass(r,low,high);//調用一趟快速排序,以樞軸元素爲界劃分兩個子表
		QKSort(r,low,pos-1);//對左部子表調用快速排序
		QKSort(r,pos+1,high);//對右部子表調用快速排序
	}
}
//選擇排序的基本思想:每一趟在n-i+1的記錄中選取關鍵字最小的記錄作爲有序序列中的第i個記錄
//簡單選擇排序
void SelectSort(int r[],int length){
	//對記錄數組作簡單選擇排序,length爲數組的長度
	int i,j,k,n,x;
	n=length;
	for(i=1;i<=n-1;i++){
		k=i;
		for(j=i+1;j<=n;j++){
			if(r[j]<r[k]){
				k=j;	
			}	
		}
		if(k!=i){
			x=r[i];
			r[i]=r[k];
			r[k]=x;
		}
	}
}
//樹形選擇排序:先把待排序的n個記錄的關鍵字兩兩進行比較取出較小者。然後再n/2個較小者中,採用同樣的方法進行比較選出每兩個中的較小者,
//如此反覆,直至選出最小關鍵字爲止。
//堆排序
//調整堆
void sift(int r[],int k,int m){
	//假設人r[k...m]是以r[k]爲根的完全二叉樹,且分別以r[2k]和r[2k+1]爲根的左,右子樹爲根爲大根堆,調整r[k],使整個序列r[k...m]滿足推得性質
	int i,j,t,x;
	t=r[k];
	x=r[k];
	i=k;
	j=2*i;
	while(j<=m){
		if(j<m && r[j]<r[j+1]){
			j=j+1;//若存在右子樹,且右子樹根的關鍵字大,則沿右分支篩選
		}
		if(x>=r[j]){
			break;
		}
		else{
			r[i]=r[j];
			i=j;
			j=2*i;
		}//繼續篩選
	}
	r[i]=t;//r[k]填入到恰當得位置
}
//建初堆.將一個任意序列看成是對應的完全二叉樹,由於葉節點可以視爲單元素的堆,因而可以反覆利用上述調整堆算法(篩選法)
//自低向上把所有子樹調整爲堆。
void create_heap(int r[],int length){
	int n,i;
	n=length;
	for(i=n/2;i>=1;--i){
		sift(r,i,n);
	}
}
//堆排序算法實現
void HeapSort(int r[],int length){
	int i,n,b;
	create_heap(r,length);
	n=length;
	for(i=n;i>=2;i--){
		b=r[1];//將堆頂記錄和堆中的最後一個元素和、交換。
		r[1]=r[i];
		r[i]=b;
		sift(r,1,i-1);
	}
}
//歸併排序:它的基本思想是基於合併,將兩個或者兩個以上有序表合成一個新的有序表。
//算法思想:假設初始序列含有n個記錄,首先江浙n個記錄看成n個有序的子序列,每個子序列的長度爲1,然後兩兩合併,得到n/2個長度爲2的有序子序列。
//如此重複,直至得到一個長度爲n的有序序列爲止。
//相鄰兩個有序子序列的合併算法
void Merge(int r1[],int low,int mid,int high,int r2[]){
	//已知r1[low..mid]和r1[mid+1,high]分別按關鍵字有序排列,將它們合併成一個有序序列,存放在r2[low...high]
	int i,j,k;
	i=low;j=mid+1;k=low;
	while((i<=mid)&&(j<=high)){
		if(r1[i]<=r1[j]){
			r2[k]=r1[i];i++;
		}
		else{
			r2[k]=r1[j];j++;
		}
		++k;
	}
	while(i<=mid){
		r2[k]=r1[i];i++;k++;
	}
	while(j<=high){
		r2[k]=r1[j];k++;j++;
	}
}
//2-路歸併排序的遞歸算法
void MSort(int r1[],int low,int high,int r3[]){
	//r1[low..high]經過排序後放在r3[low...high]中,r2作爲輔助空間
	int mid;
	int r2[N+1];
	if(low==high) r3[low]=r1[low];
	else{
		mid=(low+high)/2;
		MSort(r1,low,mid,r2);
		MSort(r1,mid+1,high,r2);
		Merge(r2,low,mid,high,r3);
	}
}
void MergeSort(int r[],int n){
	MSort(r,1,n,r);
}
main(){
	int temp[]={0,48,62,35,77,55,14,35,98};
	MergeSort(temp,8);
	print(temp,8);
}

 

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