常用排序算法的c++語言實現(2)

承接上一篇的常用排序算法的c++語言實現
**4.希爾排序:**把記錄按下表的一定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止
**5.快速排序:**通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
**6.歸併排序:**一種穩定的排序方法。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲2-路歸併。
**7.堆排序:**利用堆這種數據結構所設計的一種排序算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。

#include<iostream>
using namespace std;

//遍歷數組
void traverse(int* arr, int len) {
	for (int i = 0; i < len; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;
}
//交換函數
void swap(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}
//冒泡排序
void Bubble_Sort(int* a, int len) {
	for (int i = 0; i < len - 1; i++) {
		int flag = 0;
		for (int j = 0; j < len - 1 - i; j++) {
			if (a[j] > a[j+1]) {
				swap(a[j], a[j+1]);
				flag = 1;
			}
		}
	    if (flag == 0)break;
	}
}
//選擇排序,不穩定
void Selection_Sort(int* arr, int len) {
	for (int i = 0; i < len - 1; i++) {
		int index = i;
		for (int j = 1 + i; j < len; j++) {
			if (arr[index] > arr[j]) {
				index = j;
			}
		}
		swap(arr[index], arr[i]);
	}
}
//插入排序
void Insertion_Sort(int* arr, int len) {
	for (int i = 0; i < len-1 ; i++) {
		for (int j = i; j >=0; j--) {
			if (arr[j] > arr[j + 1]) {
				swap(arr[j], arr[j + 1]);
			}
			else break;
		}
	}
}
//希爾排序:更高效的插入排序,不穩定
void Shell_Sort(int* arr, int len) {
	for (int gap = len / 2; gap > 0; gap /= 2) {
		for (int i = gap; i < len; i++) {
			for (int j = i - gap; j >= 0; j -= gap) {
				if (arr[j] > arr[j + gap]) {
					swap(arr[j], arr[j + gap]);
				}
				else break;
			}
		}
	}
}
//快速排序,不穩定
void Quick_Sort(int* arr, int left, int right) {
	int l = left;// 左下標
	int r = right;// 右下標
	int pivot = arr[(left + right) / 2];// 找到中間的值
	// 將比pivot小的值放在其左邊,比pivot大的值放在其右邊
	while (l < r) {
		// 在pivot左邊尋找,直至找到大於等於pivot的值才退出
		while (arr[l] <pivot) {
			l += 1;// 將l右移一位
		}
		// 在pivot右邊尋找,直至找到小於等於pivot的值才退出
		while (arr[r] > pivot) {
			r -= 1;// 將r左移一位
		}
		if (l >= r) {
			// 左右下標重合,尋找完畢,退出循環
			break;
		}
		// 交換元素
		swap(arr[r], arr[l]);
		//倘若發現值相等的情況,則沒有比較的必要,直接移動下標即可
		// 如果交換完後,發現arr[l]==pivot,此時應將r左移一位
		if (arr[l] == pivot) {
			r -= 1;
		}
		// 如果交換完後,發現arr[r]==pivot,此時應將l右移一位
		if (arr[r] == pivot) {
			l += 1;
		}
	}
	// 如果l==r,要把這兩個下標錯開,否則會出現無限遞歸,導致棧溢出的情況
	if (l == r) {
		l += 1;
		r -= 1;
	}
	// 向左遞歸
	if (left < r) {
		Quick_Sort(arr, left, r);
	}
	// 向右遞歸
	if (right > l) {
		Quick_Sort(arr, l, right);
	}
}
//歸併排序
void merge(int* arr, int left, int right, int mid, int* temp) {
	int i = left; // 初始化i,左邊有序序列的初始索引
	int j = mid + 1;// 初始化j,右邊有序序列的初始索引(右邊有序序列的初始位置即爲中間位置的後一個位置)
	int t = 0;// 指向temp數組的當前索引,初始爲0
	// 先把左右兩邊的數據(已經有序)按規則填充到temp數組
	// 直到左右兩邊的有序序列,有一邊處理完成爲止
	while (i <= mid && j <= right) {
		// 如果左邊有序序列的當前元素小於或等於右邊有序序列的當前元素,就將左邊的元素填充到temp數組中
		if (arr[i] <= arr[j]) {
			temp[t] = arr[i];
			t++;// 索引後移
			i++;// i後移
		}
		else {
			// 反之,將右邊有序序列的當前元素填充到temp數組中
			temp[t] = arr[j];
			t++;// 索引後移
			j++;// j後移
		}
	}
	// 把有剩餘數據的一邊的元素填充到temp中
	while (i <= mid) {
		// 此時說明左邊序列還有剩餘元素
		// 全部填充到temp數組
		temp[t] = arr[i];
		t++;
		i++;
	}
	while (j <= right) {
		// 此時說明左邊序列還有剩餘元素
		// 全部填充到temp數組
		temp[t] = arr[j];
		t++;
		j++;
	}
	// 將temp數組的元素複製到原數組
	t = 0;
	int tempLeft = left;
	while (tempLeft <= right) {
		arr[tempLeft] = temp[t];
		t++;
		tempLeft++;
	}
}
void Merge_Sort(int*arr, int left, int right, int* temp) {
	// 分解
	if (left < right) {
		int mid = (left + right) / 2;// 中間索引
		// 向左遞歸進行分解
		Merge_Sort(arr, left, mid, temp);
		// 向右遞歸進行分解
		Merge_Sort(arr, mid + 1, right, temp);// mid + 1,中間位置的後一個位置纔是右邊序列的開始位置
		// 每分解一輪便合併一輪
		merge(arr, left, right, mid, temp);
	}
}
//堆排序
// 調整使之成爲最大堆
 void adjustHeap(int*arr, int i,int len) {
	int maxIndex = i;
	//如果有左子樹,且左子樹大於父節點,則將最大指針指向左子樹
	if (i * 2 < len && arr[i * 2] > arr[maxIndex])
		maxIndex = i * 2;
	//如果有右子樹,且右子樹大於父節點,則將最大指針指向右子樹
	if (i * 2 + 1 < len && arr[i * 2 + 1] > arr[maxIndex])
		maxIndex = i * 2 + 1;
	//如果父節點不是最大值,則將父節點與最大值交換,並且遞歸調整與父節點交換的位置。
	if (maxIndex != i) {
		swap(arr[maxIndex],arr[i]);
		adjustHeap(arr, maxIndex,len);
	}
}
 //構建最大堆函數
 void Build_MaxHeap(int* arr, int len) {
	 //從最後一個非葉子節點開始向上構造最大堆
	 for (int i = (len / 2 - 1); i >= 0; i--) {
		 adjustHeap(arr, i, len);
	 }
 }
 void Heap_Sort(int* arr, int len) {
	 //1.構建最大堆
	 Build_MaxHeap(arr, len);
	 //2.循環將堆首位(最大值)與末位交換,然後在重新調整最大堆
	 while (len > 0) {
		 swap(arr[0], arr[len - 1]);
		 len--;
		 adjustHeap(arr, 0,len);
	 }
 }
int main() {
	int arr[10] = { 1,3,5,7,9,2,4,6,8,0 };
	int len = sizeof(arr) / sizeof(arr[0]);
	traverse(arr, len);
	Bubble_Sort(arr, len);
	Selection_Sort(arr, len);
	Insertion_Sort(arr, len);
	Shell_Sort(arr,len);
	int left = 0;
	int right = 9;
	Quick_Sort(arr, left, right);
	int* temp = new int[10];
	Merge_Sort(arr, left, right,temp);
	Heap_Sort(arr, len);
	traverse(arr, len);
	system("pause");
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章