1. 程式人生 > >各種排序演算法的場景以及c++實現(插入排序,希爾排序,氣泡排序,快速排序,選擇排序,歸併排序)

各種排序演算法的場景以及c++實現(插入排序,希爾排序,氣泡排序,快速排序,選擇排序,歸併排序)

對現有工作並不是很滿意,所以決定找下一個坑。由工作中遇到排序場景並不多,大都是用氣泡排序,太low,面試又經常問到一些排序演算法方面的東西。剛好讓小學妹郵的資料結構也到了。就把各種排序演算法重新總結一下,以作留存。

排序分為內部排序和外部排序,內部排序是在記憶體中排序。外部排序是由於排序記錄量太大,記憶體一次放不下全部記錄,排序過程中需要對外部儲存訪問的排序過程。外部排序用到的場景比較少,所以本次總結的都是內部排序。

排序安全:相同的元素相對位置不變,是排序安全,反之是不安全。

一,直接插入排序

基本思路:把一個元素插入到已排好的有序表中。(初始時認為是隻有一個有序元素為有序表和其他無序元素)

應用場景:基本有序時複雜度為n。

是否排序安全:安全。

複雜度:O(n2).

程式碼:

//直接插入排序
void CSort::InsertSort(int *a, int len)
{
for (int i = 1; i < len; i++)
{
int key = a[i];
int j = i - 1;

//當前元素做為key
while (j>=0 && a[j] > key)
{

//不是元素應當插入時的位置,全部後移
a[j + 1] = a[j];
j--;
}

//插入元素到正確位置
a[j+1] = key;
}
}

二,希爾排序 

希爾排序是直接插入排序的改進。

基本思路:先將整個待排序記錄按照增量分割成若干子序分別進行插入排序,基本有序時在進行一次直接插入排序。

實現:先使增量為長度的一半,在讓增量變為增量的一半,使序列逐漸有序,增量為1時,等於對基本有序數列進行一次直接插入排序。

應用場景:基本有序時複雜度為n。

是否排序安全:不安全。

複雜度:O(n2).

程式碼:

//希爾插入,當增量為1時就是直接插入排序
void CSort::ShellInsert(int *a, int len, int dk)
{
for (int i = dk + 1; i < len; i++)
{
int key = a[i];
int j = i - dk;
while (j >= 0 && a[j] > key)
{
a[j +dk] = a[j];
j -= dk;
}
a[j + dk] = key;
}
}

//希爾排序
void CSort::ShellSort(int *a, int len)
{
int k = len / 2;
while (k >= 1)
{
ShellInsert(a, len, k);
k = k / 2;
}
}

三,氣泡排序

基本思路:在要排序的一組數中,對當前還未排好序的範圍內的全部數,自上而下對相鄰的兩個數依次進行比較和調整,讓較大的數往下沉,較小的往上冒。即:每當兩相鄰的數比較後發現它們的排序與排序要求相反時,就將它們互換。

是否排序安全:安全

程式碼:

void CSort::BubbleSort(int *a, int len)
{
for (int i = 0; i < len; i++)
{
for (int j = i + 1; j < len; j++)
{
if (a[i] > a[j])
{
swap(&a[i], &a[j]);
}
}
}
}

四,快速排序。(氣泡排序的優化)

基本思路:選取一個元素, 把表裡的元素依次對比選取的元素,分割成2個表(此時元素以在最終的位置)。在依次對這兩個表進行重複操作。次元素所在的位置就是最終其應該在的位置。當表裡的元素數量為1時結束。

適用場景:快速排序是平均複雜度最低的排序。

是否排序安全:不安全

程式碼:

//快速排序
int CSort::Partition(int *a, int low, int high)
{
int key = a[low];
while (low < high)
{
while (low < high&&a[high] >= key) high--;
swap(&a[low],&a[high]);
while (low < high&&a[low] <= key) low++;
swap(&a[low],&a[high]);
}
return low;
}


void CSort::QuickSort(int *a, int low, int high)
{
if (low<high)
{
int index = Partition(a, low, high);
QuickSort(a, low, index - 1);
QuickSort(a, index + 1, high);
}
}

五,選擇排序(簡單選擇排序)。

基本思路:每一趟迴圈都選擇最小(大)的元素作為有序數列的第i個元素。

適用場景:

是否排序安全:不安全

程式碼:

void CSort::SelectSort(int *a, int len)
{
for (int i = 0; i < len; i++)
{
int index = i;
for (int j = i + 1; j < len; j++)
{
if (a[j] < a[index])
{
index = j;
}
}
swap(&a[index],&a[i]);
}
}

六,歸併排序。

基本思路:歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。

歸併排序示例:


複雜度:O(n)

使用場景:適用於很多元素而且無序的排序。

程式碼:

void CSort::Merge(int *r, int *rf, int i, int m, int n)
{
int j, k;
for (j = m + 1, k = i; i <= m && j <= n; ++k){
if (r[j] < r[i]) rf[k] = r[j++];
else rf[k] = r[i++];
}
while (i <= m)  rf[k++] = r[i++];
while (j <= n)  rf[k++] = r[j++];
}


void CSort::MergeSort(int *r, int *rf, int lenght)
{
int len = 1;
int *q = r;
int *tmp;
while (len < lenght) {
int s = len;
len = 2 * s;
int i = 0;
while (i + len < lenght){
Merge(q, rf, i, i + s - 1, i + len - 1); //對等長的兩個子表合併  
i = i + len;
}
if (i + s < lenght){
Merge(q, rf, i, i + s - 1, lenght - 1); //對不等長的兩個子表合併  
}
tmp = q; q = rf; rf = tmp; //交換q,rf,以保證下一趟歸併時,仍從q 歸併到rf  
}
}

下面附帶實現的全部原始碼。

////////////////////////////////////////////////////////////
//
//                 SortTest.h
//
////////////////////////////////////////////////////////////
#ifndef __CSORT_TEST_H__
#define __CSORT_TEST_H__

#include <stdio.h>
#include <stdlib.h>

class CSort
{
public:
	void swap(int *a,int *b);

	//直接插入排序
	void InsertSort(int *a, int len);

	//希爾排序
	void ShellInsert(int *a, int len, int dk/*增量*/);
	void ShellSort(int *a,int len);

	//快速排序
	void QuickSort(int *a,int low,int high);

	int Partition(int *a,int low,int high);

	//選擇排序
	void SelectSort(int *a,int len);

	//氣泡排序
	void BubbleSort(int *a,int len);
	
	//歸併排序
	void Merge(int *r, int *rf, int i, int m, int n);
	void MergeSort(int *r, int *rf, int lenght);
};

#endif

////////////////////////////////////////////////////////////
//
//                 SortTest.cpp
//
////////////////////////////////////////////////////////////

#include "SortTest.h"

void CSort::swap(int *a, int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//直接插入排序
void CSort::InsertSort(int *a, int len)
{
	for (int i = 1; i < len; i++)
	{
		int key = a[i];
		int j = i - 1;
		while (j>=0 && a[j] > key)
		{
			a[j + 1] = a[j];
			j--;
		}

		a[j+1] = key;
	}
}

//希爾插入,當增量為1時就是直接插入排序
void CSort::ShellInsert(int *a, int len, int dk)
{
	for (int i = dk + 1; i < len; i++)
	{
		int key = a[i];
		int j = i - dk;
		while (j >= 0 && a[j] > key)
		{
			a[j +dk] = a[j];
			j -= dk;
		}
		a[j + dk] = key;
	}
}

//希爾排序
void CSort::ShellSort(int *a, int len)
{
	int k = len / 2;
	while (k >= 1)
	{
		ShellInsert(a, len, k);
		k = k / 2;
	}
}

//快速排序
int CSort::Partition(int *a, int low, int high)
{
	int key = a[low];
	while (low < high)
	{
		while (low < high&&a[high] >= key) high--;
		swap(&a[low],&a[high]);
		while (low < high&&a[low] <= key) low++;
		swap(&a[low],&a[high]);
	}
	return low;
}

void CSort::QuickSort(int *a, int low, int high)
{
	if (low<high)
	{
		int index = Partition(a, low, high);
		QuickSort(a, low, index - 1);
		QuickSort(a, index + 1, high);
	}
}

void CSort::SelectSort(int *a, int len)
{
	for (int i = 0; i < len; i++)
	{
		int index = i;
		for (int j = i + 1; j < len; j++)
		{
			if (a[j] < a[index])
			{
				index = j;
			}
		}
		swap(&a[index],&a[i]);
	}
}

void CSort::BubbleSort(int *a, int len)
{
	for (int i = 0; i < len; i++)
	{
		for (int j = i + 1; j < len; j++)
		{
			if (a[i] > a[j])
			{
				swap(&a[i], &a[j]);
			}
		}
	}
}

void CSort::Merge(int *r, int *rf, int i, int m, int n)
{
	int j, k;
	for (j = m + 1, k = i; i <= m && j <= n; ++k){
		if (r[j] < r[i]) rf[k] = r[j++];
		else rf[k] = r[i++];
	}
	while (i <= m)  rf[k++] = r[i++];
	while (j <= n)  rf[k++] = r[j++];
}

void CSort::MergeSort(int *r, int *rf, int lenght)
{
	int len = 1;
	int *q = r;
	int *tmp;
	while (len < lenght) {
		int s = len;
		len = 2 * s;
		int i = 0;
		while (i + len < lenght){
			Merge(q, rf, i, i + s - 1, i + len - 1); //對等長的兩個子表合併  
			i = i + len;
		}
		if (i + s < lenght){
			Merge(q, rf, i, i + s - 1, lenght - 1); //對不等長的兩個子表合併  
		}
		tmp = q; q = rf; rf = tmp; //交換q,rf,以保證下一趟歸併時,仍從q 歸併到rf  
	}
}

int main()
{
	CSort sort;
	int a[10] = {10,20,32,13,9,25,23,45,56,1};
	printf("\n排序前!");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", a[i]);
	}

	//sort.InsertSort(a, 10);
	//sort.ShellInsert(a, 10, 1);
	//sort.ShellSort(a, 10);
	//sort.QuickSort(a, 0, 9);
	//sort.SelectSort(a, 10);
	//sort.BubbleSort(a, 10);

	int b[10] = { 0 };
	sort.MergeSort(a,b,10);
	printf("\n排序後!");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", a[i]);
	}
	printf("hello world!\n");
	system("pause");
	return 0;
}