1. 程式人生 > >快速排序的三種方法

快速排序的三種方法

快速排序演算法主要用到的基本演算法思想是分治演算法:排序陣列時,將陣列分為兩個小部分,然後對它們進行遞迴排序。

在本篇文章中,將採用三種方法實現快速排序。現在有陣列a定義為{ 55.3, 55.2, 59.5, 26, 53, 58, 97, 93 }。

第一種

我們給定一個t值,然後重新組織陣列a[m...n],並計算下標p,使得所有小於t的元素在p的一端,所有大於t的元素在p的另一端。我們通過一個從左到右掃描陣列的簡單for迴圈完成這一任務。排序過程如下圖所示:

                               

                                 

                                 

程式碼實現如下所示:

#include <iostream>

using namespace std;

template <typename T>
void swap(T a[], int m, int n)
{
	T temp = a[m];
	a[m] = a[n];
	a[n] = temp;
}

template <typename T1>
void sort_one(T1 a[], int m, int n)
{
	int p=m;
	T1 t = a[m];
	if (m > n)
		return;
	for (int i = m+1; i <= n; i++)
	{
		if (a[i] < t)
		{
			swap<T1>(a, ++p, i);
		}
	}
	swap<T1>(a, m, p);
	sort_one(a,m,p-1);
	sort_one(a, p + 1, n);
}


int main()
{
	double a[]= { 55.3, 55.2, 59.5, 26, 53, 58, 97, 93 };
	sort_one<double>(a, 0, 7);
	for (int i=0; i < 8; i++)
		cout << a[i]<<",";
	return 0;
}

該快速排序方法能快速完成對隨機整數陣列的排序。在具有n個相同的陣列元素時,採用插入排序時每個元素需要移動的距離都為0,總的執行時間為O(n);但該方法需要的n-1次劃分中都需要O(n)時間來去掉一個元素,所以總的執行時間為O(n)。

第二種

對於上述中出現的問題,我們引入第二種方法,使用雙向劃分避免上述中的問題。如下圖所示:

                            

下標p和q初始化為待劃分陣列的兩端。主迴圈中有兩個內迴圈,第一個內迴圈將p向右移過小元素,遇到大元素時停止;第二個內迴圈將q向左移過大元素,遇到小元素時停止。然後主迴圈測試這兩個下標是否交叉並交換他們的值。

實現程式碼如下所示:

#include <iostream>

using namespace std;

template <typename T>
void swap(T a[], int m, int n)
{
	T temp = a[m];
	a[m] = a[n];
	a[n] = temp;
}

template <typename T2>
void sort_two(T2 a[], int m, int n)
{
	if (m > n)
		return;
	T2 t = a[m];
	int p = m,q=n+1;
	while (1)
	{
		for (p++; p <= n&&a[p] < t; p++);
		for (q--; a[q]>t; q--);
		if (p > q)
			break;
		swap<T2>(a, p, q);
	}
	swap<T2>(a, m, q);
	sort_two(a, m, q - 1);
	sort_two(a, q + 1, n);
}

int main()
{
	double a[]= { 55.3, 55.2, 59.5, 26, 53, 58, 97, 93 };
	sort_two<double>(a, 0, 7);
	for (int i=0; i < 8; i++)
		cout << a[i]<<",";
	return 0;
}

如果陣列已經按升序排好了,那麼它就會圍繞最小的元素進行劃分,然後是第2小的元素,依此類推,總共需要O(n^2)的時間。

第三種

為了解決上述問題,引入隨機選擇劃分元素可以得到好的多的效能,我們通過把a[m]與a[m...n]中的一個隨機項交換實現這一點。

程式碼實現如下所示

#include <iostream>

using namespace std;

template <typename T>
void swap(T a[], int m, int n)
{
	T temp = a[m];
	a[m] = a[n];
	a[n] = temp;
}

template <typename T3>
void sort_three(T3 a[], int m, int n)
{
	if (m > n)
		return;
	swap<T3>(a, a[m], a[rand() % (n - m + 1) + m]);
	T3 t = a[m];
	int p = m, q = n + 1;
	while (1)
	{
		for (p++; p <= n&&a[p] < t; p++);
		for (q--; a[q]>t; q--);
		if (p > q)
			break;
		swap<T3>(a, p, q);
	}
	swap<T3>(a, m, q);
	sort_two(a, m, q - 1);
	sort_two(a, q + 1, n);
}

int main()
{
	double a[]= { 55.3, 55.2, 59.5, 26, 53, 58, 97, 93 };
	sort_three<double>(a, 0, 7);
	for (int i=0; i < 8; i++)
		cout << a[i]<<",";
	return 0;
}

相關推薦

【轉載】快速排序(演算法實現和非遞迴實現)

原文地址 python實現: import random a = [4,1,7,6,9,2,2,3,5,7,8,9,3,1,2,3,4,5,8,0,3,5] b = [4,1,7,6,9,2,8,0,3,5] def twoPointerSort(nums,le

快速排序(演算法實現和非遞迴實現)

快速排序(Quick Sort)是對氣泡排序的一種改進,基本思想是選取一個記錄作為樞軸,經過一趟排序,將整段序列分為兩個部分,其中一部分的值都小於樞軸,另一部分都大於樞軸。然後繼續對這兩部分繼續進行排序,從而使整個序列達到有序。 遞迴實現: void Q

java快速排序方法

public class FaskSort { private static int count0 = 0; public static void sort(int[] array){ if(array.length > 0){

快速排序方法

快速排序演算法主要用到的基本演算法思想是分治演算法:排序陣列時,將陣列分為兩個小部分,然後對它們進行遞迴排序。在本篇文章中,將採用三種方法實現快速排序。現在有陣列a定義為{ 55.3, 55.2, 59.5, 26, 53, 58, 97, 93 }。第一種我們給定一個t值,

C++結構體多級排序方法

C++結構體多級排序的三種方法 struct node{ int chinese,math; char name[15]; }; 需求:按數學成績從大到小排序  1.自定義比較器 //自定義比較函式 bool cmp(node a,node b){ return

排序演算法1——圖解氣泡排序及其實現(方法,基於模板及函式指標)

排序演算法1——圖解氣泡排序及其實現(三種方法,基於模板及函式指標) 排序演算法2——圖解簡單選擇排序及其實現 排序演算法3——圖解直接插入排序以及折半(二分)插入排序及其實現 排序演算法4——圖解希爾排序及其實現 排序演算法5——圖解堆排序及其實現 排序演算法6——圖解歸併排序及其遞迴與非

求逆序對個數的方法(歸併排序,樹狀陣列,權值線段樹)

求逆序對個數的三種方法 逆序對: 對於一個序列 a1a_1a1​,a2a_2a2​,a3a_3a3​…ana_nan​,如果存在aia_iai​>aja_jaj​且i<j,則aia_iai​和aja_jaj​為一個逆序對。 這裡將介紹3種求逆序對對數

ios 快速判斷當前網路狀態(方法)

一、利用AFN框架 //1.建立網路狀態監測管理者 AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager]; //2.監聽改變 [manager setReach

方法助力絕地求生:刺激戰場和絕地求生:全軍出擊快速上分吃雞

絕地求生:刺激戰場怎麼操作?絕地求生:全軍出擊如何吃雞攻略?很多吃雞玩家在玩全軍出擊和刺激戰場的時候總是吃不了雞怎麼辦?除了遊戲操作技術的問題還有一個客觀原因是用手機玩類似吃雞的射擊類遊戲確實不好操作。特別是在射擊的時候既要移動、瞄準還要開槍,我們只有2隻手,操作起來實在是太

快速開啟檔案命令列的方法

快速開啟檔案命令列的三種方法 方法一:Window + R  一般專業電腦工作者最常用的就是Window + R撥出執行視窗然後點選cmd進入命令列 然後直接輸入 cd + 資料夾路徑 最後敲個回車即可。 但是也有別的小夥伴存在直接c

Android快速獲取當前Activity類名的方法

據說程式猿最討厭的兩件事:一是給程式碼寫詳細的註釋;二是閱讀別人的程式碼沒註釋。在程式猿的世界裡,大部分都是接手的別人的專案,而對於一些專案文件全面,專案程式碼規範,在閱讀程式碼的時候相對輕鬆些,不至於當前是哪個Activity都不知道。But,理想是豐滿的,現

java快速尋找一個數組的最大值或最小值, min, max,方法

java 中 尋找一個數組中的最大值或最小,除了自己專門編寫一個 min 或 max 函式外,還有幾種方式方便使用。 1. 使用 stream 將一個數組放進 stream 裡面,然後直接呼叫 stream 裡的 min 或 max 函式得到最大值或最小值。 2. 使用

應對加密js的方法

-a logging ember 瀏覽器 ebp gecko afa 方法 trace 經常遇到網頁在登錄後會對用戶輸入的帳號和密碼通過js進行加密,導致模擬登錄這類網站時受到阻礙 這裏小記一下當前解決該問題的三種方法 1.利用python實現js同等加密。 2.利用sel

c# pictureBox1.Image的獲得圖片路徑的方法 winform

相對 body req () ebr art www ref clas 代碼如下:c# pictureBox1.Image的獲得圖片路徑的三種方法 winform 1.絕對路徑:this.pictureBox2.Image=Image.FromFile("D:\\00

前端下載excel文件功能的方法

light nbsp html github 支持 返回 但是 inpu brush 1 從後端接收json數據,前端處理生成excel下載 JsonExportExcel的github地址:https://github.com/cuikangjie/JsonExpor

從U盤運行Linux操作系統的方法

attach 損壞 seo 系統 alt ubunt 沒有 linux操作 ash 摘要: 從U盤運行Linux操作系統的三種方法 usb_linux_0 你或許聽說過在U盤上運行live Linux操作系統,但你知不知道可以永久的保存運行時的數據,或者直接將Linux安裝

方法打印 main函數的返回地址的值(old EIP)(用途,你懂得!)

popu tex 空間 ext 指向 多說 ret 運行 自己 這裏能夠簡單的改動隨意函數的返回地址。能夠做到自己定義EIP的指向,就可以運行當前進程空間的隨意指令,這裏僅僅是讓大家更清楚棧幀結構,沒有涉及跨進程的inline HOOK 等,後面會陸續講下讀取隨意進程

[互聯/數碼] 新站長怎麽推廣站點 新站推廣方法 推廣新站的方法

經驗 內容 ng- 個人 con top 努力 資源分享 發現 ?? 當辛辛苦苦建立了站點,每天進行信息和資訊的更新,但當我們用工具查詢時發現站點的訪問IP總是個位數。假設是論壇,這個資源分享論壇僅僅是自娛自樂的平臺。那麽新站長怎麽推廣站點?以下筆者分享個人對新站推廣方

js數值轉換的方法

num 小數點 2.3 導致 color float 註意 span defined js非數值轉換為數值的三種寫法分別為Number()、parseInt()、parseFloat()。 Number()是最復雜的。規則如下: 1.數值直接輸出; console.log

Android程序全然退出的方法

set 歷史 text post 代碼 rtp otto start lin 1. Dalvik VM的本地方法 android.os.Process.killProcess(android.os.Process.myPid()) //獲取PID,眼下獲取