數據結構——排序(Code)

閱讀代碼是件非常枯燥的事,所以儘量每一行都加的註釋,方便閱讀理解。

六、排序

(一)插入類排序
1、直接插入排序
/*
method:
	直接插入排序法
param:
	disorder_sqc	無序序列
	num				無序序列的長度
*/
int Insert_Direct(int disorder_sqc[], int num)
{
	int i = 0,j = 0;
	int temp = 0;										//臨時變量
	for (i = 1; i < num; ++i)							//i=1,默認前面已經有一個元素是有序的
	{
		temp = disorder_sqc[i];							//獲取當前值
		j = i - 1;										//獲取當前下標
		while (j >= 0 && temp < disorder_sqc[j])		//從當前下標往前依次判斷
		{
			disorder_sqc[j + 1] = disorder_sqc[j];		//當前位置元素如果比待插入值大,往後移動一個元素,給插入值騰地方
			--j;
		}
		disorder_sqc[j+1] = temp;						//插入值
	}
}
2、折半插入排序
/*
method:
	折半插入排序法
param:
	order_sqc	無序序列
	num			無序序列的長度
*/
void Half_Insert(int disorder_sqc[], int num)
{
	int i = 0;
	int temp = 0;
	int low = 0, high = 1, mid = 0,final_ = 0;			//final_指向最終插入的位置
	if (disorder_sqc[0] > disorder_sqc[1])				//默認是升序排序,如果前兩個不是升序,交換位置
	{
		temp = disorder_sqc[1];
		disorder_sqc[1] = disorder_sqc[0];
		disorder_sqc[0] = temp;
	}
	for (i = 2; i < num; ++i)
	{
		low = 0;
		high = i - 1;									//因爲有序數組在插入過程中不斷的邊長,所以high跟着變
		temp = disorder_sqc[i];							//temp獲取要插入值的臨時變量
		if (disorder_sqc[i] > disorder_sqc[high])		//如果大於最大的,則不用排序
			final_ = i;									//直接插入到最後
		else if (disorder_sqc[i] < disorder_sqc[low])	//如果小於最小的,直接放在最前方
			final_ = 0;
		else
		{
			while (low <= high)							//以low<high爲判斷標準
			{
				mid = (low + high) / 2;					//mid 因爲int型,向下取整
				if (disorder_sqc[mid] > temp)			//如果該位置的值大於要插入的值
					high = mid - 1;						//說明值在mid位置的左邊,默認爲升序排序
				else
					low = mid + 1;						//否則在mid位置的右邊,默認爲升序排序
			}
			final_ = low;								//最後獲取low的位置,即爲插入的值
		}

		for (int j = i - 1; j >= final_; --j)				//將要插入位置之後的元素依次往後挪一位
		{
			disorder_sqc[j + 1] = disorder_sqc[j];		//往後移動元素
		}
		disorder_sqc[final_] = temp;					//插入到該位置
	}
}
3、希爾排序
/*
method:
	Shell排序法
param:
	order_sqc	無序序列
	num			無序序列的長度
*/
void Shell_Sort(int disorder_sqc[], int num)
{
	int sub_num = 0;											//子序列元素數量
	int increment = num / 2;									//初始值,增量爲元素一半
	int sub_sequence[MAXSIZE][MAXSIZE];
	while (increment)											//增量每次除以2,等於0退出,則排序完成
	{
		for (int i = 0; i < num; ++i)
		{
			for (int j = i, k = 0; j < num; j += increment)		//根據增量來取值
			{
				sub_sequence[i][k++] = disorder_sqc[j];			//取出來多個子序列
				sub_num = k;
			}
			Insert_Direct(sub_sequence[i], sub_num);			//取出來一組排序一組
		}
		increment = increment / 2;								//縮小增量
	}
	for (int i = 0; i < num; i++)
	{
		disorder_sqc[i] = sub_sequence[0][i];					//將子序列排序號的元素賦值給原數組
	}
}
(二)交換類排序
1、冒泡排序
/*
method:
	冒泡排序
param:
	disorder_sqc	無序序列
	num				無序序列的長度
*/
void Bubble_Sort(int disorder_sqc[], int num)
{
	int temp = 0;											//交換時候的中間變量
	int flag = 0;											//判斷是否發生交換
	for (int j = num - 1; j > 0; --j)						//每次循環完一遍之後,保留最大值
	{	
		flag = 0;
		for (int i = 0; i < j; ++i)
		{
			if (disorder_sqc[i] > disorder_sqc[i + 1])		//如果前面的元素大於後面的
			{
				flag = 1;									//交換標誌位
				temp = disorder_sqc[i + 1];					//交換前後值
				disorder_sqc[i + 1] = disorder_sqc[i];
				disorder_sqc[i] = temp;
			}
		}
		if (flag == 0)										//如果循環一遍之後,未發生交換,則排序完成
			break;
	}
}
2、快速排序
/*
method:
	快速排序
param:
	disorder_sqc	無序序列
	low				無序序列的最小位置下標
	high			無序序列的最大位置下標
*/
void Quick_Sort(int disorder_sqc[],int low,int high)
{
	int temp = 0;											//取出要比較的值,也就是樞軸
	int i = low, j = high;									//將檢測low-high範圍內的值
	if (low < high)											//序列範圍
	{
		temp = disorder_sqc[low];							//取序列的第一個值,作爲樞軸,也就是要比較的值
		while (i < j)										//如果i<j,則序列內存在未操作的元素
		{
			while ((i < j))									//判斷序列內還有未操作的元素,先由後往前查詢
			{
				if (disorder_sqc[j] < temp)					//直到檢測到一個值小於樞軸
				{
					disorder_sqc[i] = disorder_sqc[j];		//將該位置存放小於樞軸的值
					++i;									//左側範圍向後挪一位
					break;									//這裏要退出,避免操作後範圍,
				}
				--j;										//如果經過上方break,則不操作這個
			}
			while (i < j)									//判斷序列內還有未操作的元素
			{												//查詢順序發生變化,從前往後查詢
				if (disorder_sqc[i] > temp)					//直到查詢到一個大於樞軸的值
				{
					disorder_sqc[j] = disorder_sqc[i];		//放到之前右邊範圍的位置
					--j;									//右範圍往前挪一位
					break;									//退出
				}
				++i;										//如果經過上方break,則不操作這個
			}
		}
		disorder_sqc[i] = temp;								//此時i=j,就是樞軸插入的位置
		//上面while循環之後,即爲一次樞軸比較,比樞軸小的元素都在左邊,比其大的元素都在右邊
		Quick_Sort(disorder_sqc, low, i - 1);				//按照相同操作 樞軸左邊的序列		
		Quick_Sort(disorder_sqc, i + 1, high);				//按照相同操作 樞軸右邊的序列
	}
}
(三)選擇類排序
1、簡單選擇排序
/*
method:
	簡單選擇排序
param:
	disorder_sqc	無序序列
	num				無序序列的長度
*/
void Select_Sort(int disorder_sqc[], int num)
{
	int min_sub = 0;											//存放最小值的下標
	int temp = 0;												//中間值
	int i = 0, j = 0;											//用於循環
	for (i = 0; i < num; ++i)									//循環n次
	{
		min_sub = i;											//獲取第一個元素的下標
		for (j = i+1 ; j < num ; ++j)							//執行一趟,選擇出來一個最小值
		{
			if (disorder_sqc[min_sub] > disorder_sqc[j])		//得到最小值下標
				min_sub = j;									//得到最小值的下標
		}
		temp = disorder_sqc[min_sub];							//將最小值與第一個元素互換位置
		disorder_sqc[min_sub] = disorder_sqc[i];
		disorder_sqc[i] = temp;									
	}
}
2、堆排序
  • 調整堆函數
/*
method:
	將數組中low-high位置範圍內,對low上的結點進行調整,使其爲最大
param:
	disorder_sqc	無序序列
	low				無序序列的最小位置下標
	high			無序序列的最大位置下標
*/
void Shift(int disorder_sqc[], int low, int high)						
{
	int i = low;
	int j = 2 * i;													//j是i的孩子結點
	int temp = disorder_sqc[i];										//temp表示雙親結點的值
	while (j <= high)
	{
		if ((j<high) && (disorder_sqc[j] < disorder_sqc[j + 1]))	//如果右孩子大
		{
			++j;													//將j指向右孩子
		}
		if (temp < disorder_sqc[j])									//比較雙親結點與孩子結點的大小,如果孩子結點的值大,進行交換
		{
			disorder_sqc[i] = disorder_sqc[j];						//將disorder_sqc[j]調整到雙親結點位置上
			i = j;													//修改i,j值,使其繼續向下調整
			j = 2 * i;
		}
		else
			break;
	}
	disorder_sqc[i] = temp;											//將調整的值放在最終位置	
}
  • 排序函數
/*
method:
	堆排序
param:
	disorder_sqc	無序序列
	num				無序序列的長度
	//注意:這裏將根結點作爲數組的[1]下標,可改爲零,並且一定要更改找左右孩子結點的公式
*/
void Heap_Sort(int disorder_sqc[], int num)
{
	int i = 0;
	int temp = 0;													
	for (i = num / 2; i >= 1; --i)									//建立初始堆,這裏的除以2,是爲了按層進行操作  因爲每層結點數爲2的冪
	{
		Shift(disorder_sqc, i, num);								//由下往上進行調整,確保有序,	
	}
	for (i = num; i >= 2; --i)										//爲了換出根結點的值,將其放入最終位置									
	{
		temp = disorder_sqc[1];										//取出最大值
		disorder_sqc[1] = disorder_sqc[i];
		disorder_sqc[i] = temp;										//將最大值交換到最後一個
		Shift(disorder_sqc, 1, i - 1);								//將交換之後的堆再次進行排序
	}
}
(四)歸併類排序
1、二路歸併排序(merge sort)
/*
method:
	二路歸併排序
param:
	disorder_sqc	無序序列
	low				無序序列的最小位置下標
	high			無序序列的最大位置下標
*/
void Merge_Sort(int disorder_sqc[], int low, int high)
{
	if (low < high)
	{
		int mid =(low + high) / 2;									//每次縮小組的大小
		Merge_Sort(disorder_sqc, low, mid);							//將其分爲多個組,先是一個一組,然後兩個一組,四個一組,一次類推
		Merge_Sort(disorder_sqc, mid + 1, high);					
		Quick_Sort(disorder_sqc, low, high);						//這裏是直接進行了快速排序,直接將組內值進行排序	
	}
}
(五)基數排序
/*
method:
	基數排序,比較數字
param:
	disorder_sqc	無序序列
	num				無序序列的長度
*/
void Base_Sort(int disorder_sqc[], int num)
{
	int k = 0;
	int max_bit = 0,temp = 0;										//獲取最高位
	int subscript = 0;												//存放某一位的值,下標
	int calculate_time = 1;											//分配和收集的次數,也就是全部元素往桶裏放的次數
	int barrel[MAXSIZE][MAXSIZE] = {0};								//建立桶,用來存放相同位的數組

	for (int i = 0; i < num; ++i)
	{
		temp = log(disorder_sqc[i]) / log(10);
		if (temp > max_bit)	
			max_bit = temp;											//取最高位
	}

	while (1)
	{
		for (int i = 0; i < num; ++i)								//遍歷要排序的元素
		{
			k = 0;
			subscript = disorder_sqc[i] / calculate_time % 10;		//獲取最低位的值
			while (barrel[subscript][k])	k++;					//直到判斷k不爲零
			barrel[subscript][k] = disorder_sqc[i];					//往桶裏放值
		}
		k = 0;														//將k清零,用於取值

		for (int i = 0; i < MAXSIZE; ++i)							//取出桶內的值
		{
			for (int j = 0; j < MAXSIZE; ++j)
			{
				if (barrel[i][j] == 0)								//如果桶內值爲0,說明桶內值已取完
					break;
				disorder_sqc[k++] = barrel[i][j];					//取值
				barrel[i][j] = 0;									//取完值後清零,避免干擾
			}
		}
		calculate_time *= 10;										//依次向高位比較
		if (calculate_time > pow(10.0, max_bit))
			break;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章