1. 程式人生 > >7種常見排序演算法的c++實現

7種常見排序演算法的c++實現

今天心血來潮複習了一下基本的排序演算法,實現了一下,就順便發上來咯。。

在程式碼裡做了註釋了-。-

也就不多說了,直接上程式碼吧。。

// order_algorithm.cpp: 定義控制檯應用程式的入口點。
//author: netbin

#include "stdafx.h"
#include "iostream"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <vector>

//指定陣列的大小
const int max_size = 50;

using namespace::std;

//插入排序
//時間複雜度O(n^2),空間複雜度O(n),是一個穩定演算法;
//假定該陣列有有序區和無序區:則不斷地將無序區的第一個元素取出放置於有序區的正確位置;
//從i的位置開始,從後往前依次比較,如果nums[j]小於nums[i],則交換二者的位置;
//優化:我們可以知道插入排序的前部是有序的,則如果nums[j]>=nums[i],則表明,i之前的所有元素
//都符合這個特性,那麼也就不需要再繼續比較了;
void insert_sort(vector<int> &nums) 
{
	for (int i = 0; i < nums.size(); i++) {
		for (int j = i; j > 0; j--) {
			if (nums[j] < nums[j-1]) {
				int temp = nums[j];
				nums[j] = nums[j-1];
				nums[j-1] = temp;
			}
			else
				break;
		}
	}
}

//希爾排序
//時間複雜度 O(n^1.3),準確地說希爾排序的時間複雜度與增量序列有關
//它是一個不穩定的演算法:因為可能數處於不同的組別內
//希爾排序是對插入排序的優化
void shell_sort(vector<int> &nums) 
{
	//gap是步長,步長每次減半;
	//這裡最後的gap/=2要注意。。剛開始寫成了gap/2,沒有等號,所有gap沒作用,會造成死迴圈
	for (int gap = nums.size() / 2; gap > 0; gap /= 2) {
		//從gap位置開始,相當於直接插入排序的第2個元素開始;
		for (int i = gap; i < nums.size(); i++) {
			int temp = nums[i];
			//相當於插入排序的j = i;
			//同組內的無序陣列的第一個元素的前一個數組。。。好像挺繞的-。-
			int j = i - gap;
			//同組內元素的比較
			for (; j >= 0 && nums[j] > temp; j -= gap) {
				//這裡需要注意的是j的值變化的情況;
				//第一次的j+gap=i #-。-
				//其實也就是把大於nums[i]的值都後移
				nums[j + gap] = nums[j];
			}
			//這裡需要注意的是在上面的for迴圈中,最後還會執行一次j-=gap;
			//所以這裡的j+gap會等於上面結束時j的值
			nums[j + gap] = temp;
		}
	}
}

//氣泡排序
//時間複雜度: O(n^2),空間複雜度:O(n)
//穩定性:是一個穩定演算法
void bubble_sort(vector<int> &nums) 
{
	for (int i = 0; i < nums.size()-1; i++) {
		for (int j = 0; j < nums.size() - i - 1; j++) {
			if (nums[j] > nums[j + 1]) {
				int temp = nums[j];
				nums[j] = nums[j + 1];
				nums[j + 1] = temp;
			}
		}
	}
}

//選擇排序:從無序陣列中選出最小(最大)的數,放到亂序陣列的頭部
//優化:同時選出最大和最小
void select_sort(vector<int> &nums)
{
	for (int i = 0; i < nums.size(); i++) {
		int min = i;
		for (int j = i+1; j < nums.size(); j++) {
			if (nums[j] < nums[min]) {
				min = j;
			}
		}
		int temp = nums[i];
		nums[i] = nums[min];
		nums[min] = temp;
	}
}

//快速排序
void quick_sort(vector<int> &nums, int b, int e, vector<int> &temp)
{
	int m = (b + e) / 2;
	//判斷是否只有一個元素
	if (m != b) {
		int lb = b;
		int rb = e - 1;
		for (int i = b; i < e; i++) {
			//如果當前位置等於選中元素的位置,則跳過此次迴圈,進入下一次迴圈;
			if (i == m) {
				continue;
			}
			//如果當前位置元素的值小於選中的元素,則新增到臨時陣列的左邊
			if (nums[i] < nums[m]) {
				temp[lb++] = nums[i];
			}else{
				//如果當前位置元素的值大於選中的元素,則新增到臨時陣列的右邊
				temp[rb--] = nums[i];
			}
		}
		//迴圈結束時,temp陣列中lb指向的位置就是在nums陣列中選中元素所在的位置
		temp[lb] = nums[m];
		//將temp陣列複製到nums陣列中
		for (int i = b; i < e; i++) {
			nums[i] = temp[i];
		}
		//遞迴呼叫
		quick_sort(nums,b,lb,temp);
		quick_sort(nums, lb + 1, e, temp);
	}
}


//歸併排序
//時間複雜度:O(nlogn)
//歸併排序是將元素分割為一個一個的小組,然後對每個小組再進行排序,然後再合併陣列,分而治之的思想
//這種排序的方式與希爾排序的基本思想類似
void merge_array(vector<int> &nums, int b, int m, int e, vector<int> &temp)
{
	int lb = b;
	int rb = m;
	int tb = b;
	//在合併兩個陣列時,如果左邊陣列和右邊的陣列都未空
	while (lb != m && rb != e) {
		if (nums[lb] < nums[rb]) {
			temp[tb++] = nums[lb++];
		}
		else {
			temp[tb++] = nums[rb++];
		}
	}
	//如果右邊的已經空了,而左邊沒空,就將左邊陣列的剩餘所有元素全部入陣列
	while (lb < m)
		temp[tb++] = nums[lb++];
	//如果左邊的已經空了,而右邊沒空,就將右邊陣列的剩餘所有元素全部入陣列
	while (rb < m)
		temp[tb++] = nums[rb++];
	//將此次合併存入臨時陣列的元素全部複製到nums陣列中
	for (int i = b; i < e; i++) {
		nums[i] = temp[i];
	}
}

void merge_sort(vector<int> &nums, int b, int e, vector<int> &temp)
{
	int m = (b + e) / 2;
	if (m != b) {
		//將元素分割成一個一個的
		merge_sort(nums, b, m, temp);
		merge_sort(nums, m, e, temp);
		//然後對這些元素組成的小組進行遞迴合併;
		merge_array(nums, b, m, e, temp);
	}
}

//堆排序
//建堆以及調整堆
void max_heapofy(vector<int> &nums, int beg, int end)
{
	int curr = beg;
	int child = curr * 2 + 1;
	//不是最後一個結點
	while (child < end) {
		//判斷子結點中哪個更大,用最大子節點來和父節點比較就可以了
		if (child + 1 < end && nums[child + 1] > nums[child])
			child++;
		//如果父節點小於最大子節點,就交換值
		if (nums[curr] < nums[child]) {
			int temp = nums[curr];
			nums[curr] = nums[child];
			nums[child] = temp;
			//調整之後可能會導致下面的子樹不是最大堆,故而要重新調整
			curr = child;
			child = curr * 2 + 1;
		}
		else
			//如果不需要調整,則結束此次迴圈
			break;
	}
}

void heap_sort(vector<int> &nums)
{
	int n = nums.size();
	//建堆
	for (int i = n / 2 - 1; i >= 0; i--) {
		max_heapofy(nums,i,nums.size());
	}
	//將堆頂(最大元素)和陣列的最後一個值交換,然後再調整堆
	for (int i = n - 1; i > 0; i--) {
		int temp = nums[i];
		nums[i] = nums[0];
		nums[0] = temp;
		max_heapofy(nums,0,i);
	}
}

//初始化vector陣列函式
void init_vec(vector<int> &nums)
{
	srand((unsigned)time(NULL));
	for (int i = 0; i < max_size; i++) {
		nums.push_back(rand());
	}
}
//輸出結果,並清空vector
void print_clear(vector<int> &nums)
{
	for (int i = 0; i < max_size; i++) {
		cout << nums[i] << "  ";
	}
	cout << endl;
	nums.clear();
}


int main()
{
	vector<int> nums;

	//插入排序:測試結果成功
	init_vec(nums);
	time_t start = clock();
	insert_sort(nums);
	time_t end = clock();
	cout << "插入排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);


	//希爾排序:測試結果成功
	init_vec(nums);
	start = clock();
	shell_sort(nums);
	end = clock();
	cout << "希爾排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);

	//氣泡排序:成功
	init_vec(nums);
	start = clock();
	bubble_sort(nums);
	end = clock();
	cout << "氣泡排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);

	//選擇排序:成功
	init_vec(nums);
	start = clock();
	select_sort(nums);
	end = clock();
	cout << "選擇排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);

	//快速排序:成功
	vector<int> temp(max_size);
	init_vec(nums);
	start = clock();
	quick_sort(nums,0,nums.size(),temp);
	end = clock();
	temp.clear();
	cout << "快速排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);

	//歸併排序:失敗-。- 陣列下表越界 #因為在快速排序時清空了temp陣列,所以導致了這次的陣列越界
	init_vec(temp);
	init_vec(nums);
	start = clock();
	merge_sort(nums, 0, nums.size(), temp);
	end = clock();
	temp.clear();
	cout << "歸併排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);
	

	//堆排序:失敗-。-最後一個元素沒有排好序
	//修復了 #-。-
	init_vec(nums);
	start = clock();
	heap_sort(nums);
	end = clock();
	temp.clear();
	cout << "堆排序測試結果:" << endl;
	print_clear(nums);
	printf("執行時間 : %f\n", double(end - start) / CLOCKS_PER_SEC);

	system("pause");
    return 0;
}