經典算法(六)----快速排序----圖解法讓你快速入門

引言

     只要設計到數據,就會涉及到數據的排序問題,比如給你隨機給你五個整數  3,1,5,2,4 。讓你從小到大進行排序,那我們該怎樣纔是實現對這些整數的排序呢 ?

    答案是多種多樣的,比如用插入排序、希爾排序、堆排序、歸併排序、快速排序等等,這些排序方法都可以實現對整數排序,而這篇文章要講的就是快速排序

本文將從以下幾個問題對快速排序進行分析和講解:

  1. 什麼是快速排序?
  2. 快速排序的大概過程是什麼?
  3. 怎樣用代碼實現快速排序?
  4. 快速排序的代碼詳解。

一、什麼是快速排序?

下面看百度百科對快速排序的定義:

快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。 

簡單理解:還記得歸併排序的思想嗎,歸併排序就是先分再合。而快速排序(下面簡稱快排)有一個分的過程(不是歸併排序裏的一個數組分成兩部分),快排的分一共分兩大步。

  1. 首先找一個基準數(可以選數組的任意一個位置,這篇文章選的是數組的第一個數)。第一步就是把基準數變換位置,這個位置前面的數都比基準數小,後面的數都比基準數大(這裏排序是從小到大排序)。
  2. 開始分,以基準數爲界限,分成兩部分(兩部分都不包含基準數)。再對上面的兩部分都執行上面的1過程即可。

截止到現在爲止,只需要知道快排的兩大步是什麼就可以了,下面看一個動圖:

二、快速排序的大概過程是什麼?

我們用快速排序講一個例子來說明,要排序的數組爲3,1,5,2,4.

第一步:定基準數,並把基準數移動到合適的位置。

一般來說,基準數最終的位置(在這個位置前面的數都比基準數小,後面的數都比基準數大)都在基準數起始位置的後面(我選的基準數的數組的第一個元素),那應該讓基準數移動到哪個位置呢?

我們要設置兩個哨兵 i 和 j ,第一個哨兵 i 的位置是數組第一個元素的位置,哨兵 j 的位置數數組的最後一個元素的位置

首先哨兵 j 往前移動,在不和哨兵 i 碰頭的情況下,如果發現了一個比基準數小的數,那就暫停移動,這時候輪到了哨兵 i 往後移動,在不和哨兵 j  碰頭的情況下,如果發現了一個比基準數大的數,那就停止移動,然後哨兵 i 和 哨兵 j 交換他倆的元素,下面看圖理解。

首先發現哨兵 j 比 基準數大,所以前移,移動到一個比基準數小的位置,哨兵 i 後移,移動到一個比基準數大的位置

這時候交換哨兵 i 和 j 的值。

下面繼續哨兵j前移,哨兵i後移操作,但是哨兵 j 前移發現和 i 碰頭了,那就結束哨兵的移動,把哨兵 i 和基準數的值互換

經過上面的操作,就完成了基準數的移動,達到了基準數前面的數都比基準數小,基準數後面的數都比基準數大的目的

下面看用代碼怎麼實現上面圖片的一系列操作

void QuickSort(int arr[],int first,int last)
{
	if(first>last)//控制遞歸結束 
		return ;
	int i=first,j=last;
	int temp=arr[first];//基準數
	while(i!=j)//i和j不碰頭 
	{
		//順序很重要,要先從右往左找 
		while(arr[j]>=temp&&i<j) 
			j--;
		//上面循環結束的條件有兩種,
		//一是查到了比基準數小的,
		//二是 i與j碰頭了
		while(arr[i]<=temp && i<j)
			i++; 
		//循環結束條件同上
		
		//下面交換兩個數在數組中的位置
		if(i<j) //兩個循環結束的條件都不是i和j碰頭
		{
			int t=arr[i];
			arr[i]=arr[j];
			arr[j]=t;
		} 
	} 
	//最終一定會碰頭,交換基準數和碰頭那個位置的數 
	arr[first]=arr[i];
	arr[i]=temp; 
		 
	//QuickSort(arr,first,i-1);分的前一部分 
	//QuickSort(arr,i+1,last); 分的後一部分 
}

我相信只要上面的圖片過程看懂了,那麼看懂這段代碼基本沒啥問題了。

第二步就是分了,也就是上面函數的後兩行,分成兩部分,遞歸調用

三、怎樣用代碼實現快速排序?

下面看完整的代碼

#include<iostream>
using namespace std;
//快速排序函數    不穩定 
void QuickSort(int arr[],int first,int last)
{
	if(first>last)//控制遞歸結束 
		return ;
	int i=first,j=last;
	int temp=arr[first];//基準數
	while(i!=j)//i和j不碰頭 
	{
		//順序很重要,要先從右往左找 
		while(arr[j]>=temp&&i<j) 
			j--;
		//上面循環結束的條件有兩種,
		//一是查到了比基準數小的,
		//二是 i與j碰頭了
		while(arr[i]<=temp && i<j)
			i++; 
		//循環結束條件同上
		
		//下面交換兩個數在數組中的位置
		if(i<j) //兩個循環結束的條件都不是i和j碰頭
		{
			int t=arr[i];
			arr[i]=arr[j];
			arr[j]=t;
		} 
	} 
	//最終一定會碰頭,交換基準數和碰頭那個位置的數 
	arr[first]=arr[i];
	arr[i]=temp; 
		 
	QuickSort(arr,first,i-1);//分的前一部分 
	QuickSort(arr,i+1,last); //分的後一部分 
}
//輸出數組的值
void printf(int arr[],int len)
{
	for(int i=0;i<len;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
}
int main()
{
	//要排序的數組 
	int arr[]={3, 44,38, 5,47,15,36,26,27,2 ,46,4 ,19,50,48};
	int len=15;//要排序的數組長度 
	
	//排序 
	QuickSort(arr,0,len-1);
	
	//輸出 
	printf(arr,len);
	return 0;
}

運行結果:

四、快速排序代碼詳解

  1. 實現基準數的移動,注意兩個哨兵移動時,移動要哨兵 j 先移動,然後再哨兵 i 移動
  2. 實現分的過程,注意以什麼爲分割線進行分

本文參考以及引用:

啊哈算法!

百度百科

 

如果對其他的算法還有興趣,可以點擊下面的鏈接。

  1. 經典算法(一)----冒泡排序----圖解法讓你快速入門

  2. 經典算法(二)----選擇排序----圖解法讓你快速入門

  3. 經典算法(三)----插入排序----圖解法讓你快速入門

  4. 經典算法(四)----希爾排序----圖解法讓你快速入門

  5. 經典算法(五)----歸併排序----圖解法讓你快速入門

  6. 經典算法(六)----快速排序----圖解法讓你快速入門

  7. 經典算法(七)----  堆排序 ----圖解法讓你快速入門

  8. 經典算法(八)----計數排序----圖解法讓你快速入門

  9. 經典算法(九)----基數排序----圖解法讓你快速入門

  10. 經典算法(十)----  桶排序  ----圖解法讓你快速入門

 

創作不易,如果本文對你起到了一些幫助,何不點個贊再走呢!!!

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