排序算法

#include<iostream>
using namespace std;

void out(int *arr,int len) {

	for(int i=0; i<len; i++) {
		printf("%d ",arr[i]);
	}
	printf("\n");
}

//簡單排序:選擇、冒泡、直接插入

/*
	選擇排序:從無序區選擇一個最值放進有序區。
*/
void choice(int *arr,int len) {
	for(int i=0; i<len-1; i++) {
		int min=arr[i];
		int k=i;
		for(int j=i+1; j<len; j++) {
			if(arr[j]<min) {
				min=arr[j];
				k=j;
			}
		}
		if(k!=i) {
			int temp=arr[k];
			arr[k]=arr[i];
			arr[i]=temp;
		}
	}
}

/*
	冒泡排序:動態排序,每一趟經過比較得到一個最值
*/
void bubble(int *arr,int len) {
	for(int i=0; i<len-1; i++) {
		for(int j=0; j<len-i-1; j++) {
			if(arr[j]>arr[j+1]) {
				int temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;
			}
		}
	}
}

//直接插入排序:從原序列中逐一拿來建序;從端部一直比較,得到插入位置

void direct_insert(int *arr,int len) {
	if(len<1)return;
	for(int i=1; i<len; i++) {
		if(arr[i]<arr[i-1]) {
			int j=i-1;
			while(j>=0) {
				if(arr[i]>=arr[j]) {
					break;
				}
				j--;
			}
			int temp=arr[i];
			for(int k=i-1; k>=j+1; k--) {
				arr[k+1]=arr[k];
			}
			arr[j+1]=temp;
		}
	}
}

/*
	希爾排序(直接插入排序的改進):間隔gap分組,直到gap=1;對每個分組進行直接插入排序;
*/

void shell(int *arr,int len,int gap,int dgap) {
	if(len<1||gap>len||gap<1||dgap>gap) {
		printf("參數錯誤!\n");
		return;//條件
	}
	while(gap>=1) { //gap逐漸減小到1,分爲gap組
		for(int i=0; i<gap; i++) {
			//對每一組進行直接插入排序
			for(int j=i; j<len; j=j+gap) {
				int t=arr[j];
				for(int k=j-gap; k>=0; k=k-gap) {
					if(t>=arr[k])break;
					int temp=arr[k+gap];
					arr[k+gap]=arr[k];
					arr[k]=temp;
				}
			}
		}
		gap=gap/dgap;
	}
}

/*
	快排(冒泡排序的改進):遞歸寫法。
	一趟排序:選擇分組的第一個元素作爲標杆key,從後往前與 key比較和從前往後與key比較,將
	分成左邊小於key的部分和key右邊大於 key的部分。
	算法:注意臨界數據
*/
void swap(int *arr,int v1,int v2) {
	int temp=arr[v1];
	arr[v1]=arr[v2];
	arr[v2]=temp;
}

void quick(int *arr,int l,int r) {
	if(l>=r)return;
	int key=arr[l];
	int i=l;
	int j=r;
	while(i!=j) {
		while(arr[j]>=key&&j>i) {
			j--;
		}
		swap(arr,i,j);
		while(arr[i]<=key&&j>i) {
			i++;
		}
		swap(arr,i,j);
	}
	quick(arr,l,i-1);
	quick(arr,i+1,r);
}
//快排的遞推寫法
void quick2(int *arr,int l,int r) {

}

/*
	堆排序算法(選擇排序的改進):主要實現在結點下滑算法 。
	1. 初始堆(這裏建成最大堆)
		將數組元素邏輯上構造成完全二叉樹,在從非葉結點到根結點依次執行下滑。
	2. 調整堆
		將根結點和最後一個無序區葉結點交換,然後將交換後的葉結點歸爲有序區,直到有序區的個數爲n-1;
*/
void glidedown(int *arr,int len,int index) {
	if(index>=len)return;
	if(index*2+1<len) { //有左海子
		if(index*2+2<len) { //並且有右孩子
			if(arr[index*2+1]<arr[index*2+2]) { //下滑到最大的那個孩子
				if(arr[index]<arr[index*2+2]) {
					swap(arr,index,index*2+2);
					glidedown(arr,len,index*2+2);
				}
			} else {
				if(arr[index]<arr[index*2+1]) {
					swap(arr,index,index*2+1);
					glidedown(arr,len,index*2+1);
				}
			}
		} else { //有左海子,沒有右孩子
			if(arr[index]<arr[index*2+1]) {
				swap(arr,index,index*2+1);
				glidedown(arr,len,index*2+1);
			}
		}
	}
}

void heap(int *arr,int len) {
	//最後一個非葉結點下標
	int ny_index=(len-1-1)/2;
	//1. 造初始堆
	for(int i=ny_index; i>=0; i--) {
		glidedown(arr,len,i);
	}

	printf("初始堆:\n");
	out(arr,len);

	//2. 調整堆(從最後一個無序區結點開始調整,調整n-1次)
	int count=0;
	for(int j=len-1; j>=1; j--) {
		swap(arr,0,j);
		count++;
		int ny_index2=(j-1)/2;
		for(int k=ny_index2; k>=0; k--) {
			glidedown(arr,len-count,k);
		}
	}
}

/*
	歸併排序:採用分治法。
	將兩個有序的數列合併爲一個有序數列
	合併算法:1. 有一個存放有序序列的空間
			  2. 兩個指針分別指向兩個有序數列起始位置
			  3. 將指針所比較的最值放進有序空間,指針移動
			  上面的2,3再循環完成兩序列的合併 
*/ 

void merge_two(int *arr,int *temp,int start,int mid,int end){
	int i=start;
	int j=mid+1;
	int k=0;
	while(i<=mid&&j<=end){
		if(arr[i]<arr[j]){
			temp[k++]=arr[i++];
		}else{
			temp[k++]=arr[j++];
		}
	}
	while(i<=mid){
		temp[k++]=arr[i++];
	}
	while(j<=end){
		temp[k++]=arr[j++];
	}
	//注意這裏 
	for(int h=0;h<k;h++){
		arr[start++]=temp[h];
	}
}

void merge(int *arr,int *temp,int start,int end){
	if(start>=end)return;
	int mid=(start+end)/2;
	merge(arr,temp,start,mid);
	merge(arr,temp,mid+1,end);
	merge_two(arr,temp,start,mid,end);
} 

/*
	排序算法選擇:1.數據的量n的大小,2.數據的分佈 3. 穩定性(是否改變原相同數值的相當位置) 
	1. 若n較小,可採用直接插入排序法或選擇排序法
	2. 若n較小且數據分佈有序,可以採用直接插入排序法或冒泡排序法
	3. 若n大,應採用快排,堆排序,或歸併排序 
*/ 

int main() {
	int a[]= {10,4,5,8,3,2,1,7,6,9};
	//choice(a,10);
	//bubble(a,10);
	//direct_insert(a,10);
	//shell(a,10,10,2);
	//quick(a,0,9);
	//heap(a,10);
	printf("輸出結果:\n");
	int temp[10];
	merge(a,temp,0,9);
	out(a,10);
	return 0;
}

發佈了81 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章