一篇文章快速搞懂十大排序算法(C++實現源碼)

十大排序算法函數聲明

在這裏插入圖片描述

時間複雜度表

在這裏插入圖片描述

主函數

#include<iostream>
using namespace std;

void BubbleSort(int length, int array[]);//冒泡排序
void SelectSort(int length, int array[]);//選擇排序
void InsertSort(int length, int array[]);//插入排序
void ShellSort(int length, int array[]);//希爾排序
void MergeSort(int length, int array[]);//歸併排序
void QuickSort( int begin,int end,int array[]);//快速排序
void Swap(int i, int j, int array[]);//交換數組內的兩個元素
int Partition(int begin, int end, int array[]);//快排中分割函數,結果返回中間項
void CountSort(int length, int array[]);//計數排序
void BucketSort(int length, int array[]);//桶排序
void RadixSort(int length, int array[]);//基數排序


int main() {
	int array[6] = { 2,9,1,5,3,6 };
	cout << "排序前";
	for (int i = 0; i < 6; i++)
	{
		cout << array[i]<<",";
	}
	cout << endl;
	//BubbleSort(6, array);
	//SelectSort(6, array);
	//InsertSort(6, array);
	//ShellSort(6, array);
	QuickSort(0, 5, array);
	cout << "排序後";
	for (int i = 0; i < 6; i++)
	{
		cout << array[i] << ",";
	}
	system("pause");
	return 0;
}

1冒泡排序(加入flag標記簡單優化)



void BubbleSort(int length, int array[])//冒泡排序,注意flag的位置
{
	for (int i = 0; i < length; i++)
	{
		bool flag = true;//初始flag,一趟排序剛開始
		for (int j = 0; j < length-i-1; j++)
		{
			if (array[j] > array[j + 1])
			{
				int temp = array[j];
				array[j] = array[j + 1];
				array[j + 1] = temp;
				flag = false;//只要完成過一次交換flag就爲false
			}
		}

		if (flag)//如果flag一次冒泡後仍爲true說明不需要交換,排序已經完成,不必要繼續浪費資源
			return;//退出循環排序完成
	}
}

2插入排序

void InsertSort(int length, int array[])//插入排序
{
	int current;
	for (int i = 0; i < length-1; i++)//a[i+1]項限制,第一項默認排好序,
	{
		current = array[i + 1];//將需要操作位置的值保存在current中,可以理解爲騰出空位,從第二項開始向後
		int preindex = i;//current的前一項下標
		while (preindex>=0 && array[preindex]> current)//如果前面項每次都大於固定current值 ,最終前項爲a[0]項
		{
			array[preindex + 1] = array[preindex];//前項值覆蓋後項,不同於冒泡的交換,二是直接覆蓋,
			preindex--;//每次向前遍歷
		}
		array[preindex+1] = current;//覆蓋到前項比後項小,current直接賦值給剛剛移動過剩下的空位
	}
}

3希爾排序(優化插排)

void ShellSort(int length,int array[])//希爾排序O(nlog2n),優化插排
{
	int temp, gap = length / 2;//初始定義gap爲整個數組長度的一半
	while (gap>0)
	{
		for (int i = gap; i < length; i++)
		{
			temp = array[i];//i=gap,gap+1....
			int preIndex = i - gap;
			while (preIndex>=0&& array[preIndex]>temp)
			{
				array[preIndex + gap] = array[preIndex];
				preIndex -= gap;
			}
			array[preIndex + gap] = temp;
		}
		gap /= 2;
	}
	
}

4選擇排序(選擇最小元素下標)

void SelectSort(int length,int array[]) {//選擇排序,選擇最小值下標,注意比較雙方
	for (int i = 0; i < length-1; i++) {
		int minindex =i;//初始指定i爲最小元素下標
		for (int j = minindex; j < length - 1; j++) {
			if (array[minindex] > array[j + 1]) {//下一個與最小值下標對應的元素比較
				minindex = j + 1;//選出最小值下標
			}//比較條件下標j/j+1: j+1與length-1一組,j和length一組
		}
		int temp = array[i];//最小值與當前最小值下標位置的元素交換
		array[i] = array[minindex];
		array[minindex] = temp;
	}
}

5歸併排序(優化選擇排序)



 void Mergesort( int L, int R,int array[])//歸併排序O(nlogn),優化選擇排序
 
 {
	 if (L < R)
	 {
		 int mid = L + ((R - L) >> 1);//>>1右移1位,等價於/2但是餘數直接捨去
		 Mergesort( L, mid,array);//左邊歸併排序,使左子序列有序
		 Mergesort( mid + 1, R,array);//右邊歸併排序,使得右子序列有序
		 Merge( L, mid, R,array);//合併左右兩個有序子序列
	 }
}

 void Merge( int L, int mid, int R,int array[])//歸併函數
 {
	 
    int *temp= new int[R - L + 1];//新建一個原數組一樣大的臨時數組temp
    int i = 0;//臨時數組的下標
    int p1 = L;//左側指針
    int p2 = mid + 1;//右側指針
    // 比較左右兩部分的元素,哪個小,把那個元素填入temp中
    while(p1 <= mid && p2 <= R) {
        temp[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];
    }

    // 上面的循環退出後,把剩餘的元素依次填入到temp中
    // 以下兩個while只有一個會執行
    while(p1 <= mid) {//1左側剩餘元素,依次全部移入
        temp[i++] = array[p1++];
    }
    while(p2 <= R) {//2右側剩餘元素
        temp[i++] = array[p2++];
    }
    // 把最終的排序的結果複製給原數組
	for (i = 0; i < R - L +1; i++) {//R-L+1是當前動態數組temp的大小
		array[L + i] = temp[i];
	}
	/*或者用下面的方法賦值
	i = 0;
	while (L <= R)
	{
		array[L++] = temp[i++];
	}*/
	delete[]temp;//別忘了釋放內存空間
}

6.1快速排序(單向掃描)

void Swap(int i, int j, int array[])//交換數組內兩個元素
 {
	 int temp;
	 temp = array[i];
	 array[i] = array[j];
	 array[j] = temp;
 }
void QuickSort(int begin, int end, int array[])//快速排序
{
	 if (begin<end)
	 {
		 int mid = Partition(begin, end, array);//mid返回中間項
		 QuickSort(begin, mid-1, array);//遞歸調用,對mid左邊的進行快排
		 QuickSort(mid + 1,end, array);//遞歸調用,對mid右邊的進行快排
	 }

}


int Partition(int begin, int end, int array[])//快排中分割函數,結果返回中間項
{
	int pivot = array[begin];//初始中間項值=首元素
	int sp = begin + 1;//掃描指針下標
	int bigger = end;//bigger指針初始在尾部
	while (sp<=bigger)//當掃描指針位於bigger左邊或者重合,
	{
		if (array[sp] > pivot)//如果掃描到的值大於中間項值
		{
			Swap(sp,bigger,array);//交換兩者
			bigger--;//左移1位
		}
		else//<=中間項
		{
			sp++;//繼續向後掃描
		}
	}//此時sp指向最後一個比中間項(首元素)大的值,bigger指向最後一個<=中間項的元素
	Swap(begin, bigger, array);//交換,此時新的bigger位置爲中間項(值是初始的中間項值)。左邊都是小的,右邊都是大的
	return bigger;//返回中間項bigger(即pivot)
}

6.2快速排序(雙向掃描法)


int DoubblePartition(int begin,int end,int array[])//雙向掃描法左右指針left,right
{
	int pivot = array[begin];
	int left = begin + 1;//左側指針指向pivot後1個元素
	int right = end;//右側指針指向尾元素
	while (left<=right)
	{
		if (array[left]<=pivot && left <= right)//左指針掃描元素都小於pivot
		{//最終arrayleft肯定是大於pivot
			left++;//繼續往右
		}
		if (array[right] > pivot&&left <= right)//右指針都大於pivot
		{//最終array[right]肯定是小於pivot
			right--;//繼續向左
		}
		//注意!:上面2個加上left <= right條件防止,排序完成後left和right再次移動,因爲最後一次left會一直往後跑,外層循環不一定控制的住內層循環
		//雖然我測試很多次並沒有遇到這個情況。。
		else if(left<right)//以上兩者都不滿足,左右指針停止,條件left!=right等於時候交換,沒有意義的
		{
			Swap(left, right,array);//先交換二者值,再繼續掃描
			
		}
	}
	Swap(begin, right, array);
	return right;
}

void DoubbleQuickSort(int begin, int end, int array[])//雙向掃描快排
{
	if (begin < end)
	{
		int mid = DoubblePartition(begin, end, array);//mid返回中間項
		DoubbleQuickSort(begin, mid - 1, array);//遞歸調用,對mid左邊的進行快排
		DoubbleQuickSort(mid + 1, end, array);//遞歸調用,對mid右邊的進行快排
	}
}

7堆排序


8計數排序


9桶排序


10基數排序


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章