JAVA算法之高級排序

本章介紹兩種高級排序尸折,希爾排序和快速排序妆艘,這兩種排序比之前講到的簡單排序都要快很多效扫;希爾排序大約需要O(N*(logN)2)的時間,快速排序的時間復(fù)雜度為(N*logN)席覆,這兩種算法和我們在講遞歸的時候講到的歸并排序不同史辙,不需要大量的輔助存儲空間,快速排序是所有通用排序算法中最快的排序算法娜睛。

希爾排序:

希爾排序是基于插入排序的髓霞,希爾排序在插入排序的基礎(chǔ)之上通過加大插入排序元素之間的間隔,并在這些間隔元素之間進行插入排序畦戒,使數(shù)據(jù)實現(xiàn)大跨度的移動方库,從而使排序更有效率,我們習(xí)慣將排序時數(shù)據(jù)項之間的間隔稱為增量障斋,用h來表示纵潦,下圖表示了十個數(shù)據(jù)項,以增量為4進行第一趟排序后的結(jié)果

通過上面的一趟排序之后我們可以看到元素離他們的最終有序序列位置都很近了垃环,希爾排序就是通過創(chuàng)建這種交錯有序的數(shù)據(jù)項集合邀层,從而提高排序的效率,當(dāng)上面完成了4增量的排序之后遂庄,就可以進行普通的插入排序寥院,這樣就比普通的插入排序的效率要高很多。

上面對于有十個數(shù)據(jù)項的數(shù)組初始增量我們設(shè)置為4涛目,對于數(shù)據(jù)項更大的數(shù)組我們的初始增量也應(yīng)該設(shè)置得更大秸谢,這里我們使用Knuth提出的間隔序列,序列的通項表達式為h=3*h+1霹肝,假設(shè)我們數(shù)據(jù)項的個數(shù)為100估蹄,那么通過Knuth間隔序列1,4,13,40,121,364,1093這里1093大于了我們的數(shù)據(jù)項1000,所以我們?nèi)〕跏嫉脑隽繛?64然后通過Knuth間隔序列依次減小我們的增量值沫换,最終達到我們想要的一個個排序的效果臭蚁,接下來我們給出希爾排序的java代碼

public class ArrayShell {

public long[] theArray;

private int nElems;

public ArrayShell(int size) {

this.theArray = new long[size];

this.nElems = 0;

}

public void insert(long value) {

theArray[nElems++] = value;

}

public void shellSort() {

//首先找到初始增量

int h = 1;

int outer, inner;

while (h <= nElems/3) {

h = 3 * h + 1;

}

while (h > 0) {

//以下就是普通的插入排序,只是步長換為h即可

for (outer = h; outer < nElems; outer++) {

long temp = theArray[outer];

//增量為h讯赏,所以我們首個比較的元素從h開始垮兑,h和第一個索引為0的元素比較大小、h+1和索引為1比較是否交換漱挎。然后以此類推

inner = outer;

while (inner > h - 1 && temp < theArray[inner - h]) { //需要進行數(shù)據(jù)交換的元素的滿足條件

theArray[inner] = theArray[inner - h];

inner -= h;

}

theArray[inner] = temp;

}

//從最大增量一直遞減到1做插入排序

h = (h - 1) / 3;

}

}

}

希爾排序中間隔序列互質(zhì)很重要系枪,他能是每一趟排序更有可能保持前一趟已排序好的效果。

快速排序

快速排序是基于劃分算法之上的一種排序算法识樱,首先我們介紹一下劃分算法的基本原理

劃分

劃分的基本原理就是把數(shù)據(jù)分為兩組嗤无,使關(guān)鍵值大于特定值的數(shù)據(jù)在一組震束,使關(guān)鍵值小于特定值的數(shù)據(jù)在另一組,比如我們?nèi)粘I钪袑⒓揖嚯x辦公點15km以內(nèi)和以外的雇員分為兩組当犯。劃分算法中我們將兩個標(biāo)記分別指向數(shù)組的兩頭垢村,左邊的標(biāo)記leftPtr ,向右移動嚎卫,右邊的標(biāo)記 rightPtr嘉栓,向左移動,當(dāng)leftPtr遇到比樞紐小的數(shù)據(jù)項時拓诸,繼續(xù)向右移動侵佃,當(dāng)遇到比樞紐大的數(shù)據(jù)項時就停下來,同樣當(dāng)rightPtr遇到比樞紐大的數(shù)值的時候繼續(xù)向左移動奠支,遇到比樞紐小的就停下來馋辈,然后需要交換這兩個數(shù)據(jù)項。交換之后繼續(xù)移動指針倍谜,重復(fù)上面的步驟迈螟,知道兩個標(biāo)記的值相等的時候則劃分算法完成。

接下來我們看劃分算法的java代碼

class ArrayPar {

public Long[] theArray;

private int nElems;

public ArrayPar(int max) {

theArray = new Long[max];

this.nElems = 0;

}

public void insert(Long value) {

theArray[nElems] = value;

nElems++;

}

public int partitionIt(int leftPtr, int rightPtr, long pivot) {

while (true) {

//當(dāng)leftPtr遇到比樞紐小的數(shù)據(jù)項時尔崔,繼續(xù)向右移動(即 leftPtr++)答毫,當(dāng)遇到比樞紐大的數(shù)據(jù)項時就停下來

while (leftPtr < rightPtr && theArray[leftPtr] <= pivot) //防止索引越界加上leftPtr

leftPtr++;

//當(dāng)rightPtr遇到比樞紐大的數(shù)據(jù)項時,繼續(xù)向左移動(即 rightPtr--)季春,當(dāng)遇到比樞紐大的數(shù)據(jù)項時就停下來

while (rightPtr > leftPtr && theArray[rightPtr] >= pivot)

rightPtr--;

//當(dāng)leftPtr標(biāo)記大于等于right標(biāo)記的時候結(jié)束外層循環(huán)洗搂,否則交換兩個標(biāo)記的數(shù)據(jù)項

if (leftPtr >= rightPtr)

break;

else

swap(leftPtr, rightPtr);

}

return leftPtr;

}

/**交換數(shù)據(jù)方法*/

public void swap(int dex1, int dex2) {

long temp = theArray[dex1];

theArray[dex1] = theArray[dex2];

theArray[dex2] = temp;

}

}

快速排序

快速排序的執(zhí)行時間為O(N*logN)級,快速排序是基于劃分算法之上的载弄,利用遞歸的思想的一種排序算法耘拇,這里我們選擇數(shù)組的最右邊的元素作為樞紐,在劃分算法完成之后侦锯,需要在之前的算法的基礎(chǔ)上加一步驼鞭,將樞紐項和右數(shù)組的起始項進行位置交換秦驯,交換后的樞紐值的順序就是最終的順序尺碰,然后在利用遞歸將劃分后的左右數(shù)組進行上述步驟。首先我們來看看快速排序的java代碼

class ArrayPar {

public Long[] theArray;

private int nElems;

public ArrayPar(int max) {

theArray = new Long[max];

this.nElems = 0;

}

public void insert(Long value) {

theArray[nElems] = value;

nElems++;

}

public int partitionIt(int leftPtr, int rightPtr, long pivot) {

int right = rightPtr;

while (true) {

//當(dāng)leftPtr遇到比樞紐小的數(shù)據(jù)項時译隘,繼續(xù)向右移動(即 leftPtr++)亲桥,當(dāng)遇到比樞紐大的數(shù)據(jù)項時就停下來

while (leftPtr < rightPtr && theArray[leftPtr] <= pivot) //防止索引越界加上leftPtr

leftPtr++;

//當(dāng)rightPtr遇到比樞紐大的數(shù)據(jù)項時,繼續(xù)向左移動(即 rightPtr--)固耘,當(dāng)遇到比樞紐大的數(shù)據(jù)項時就停下來

while (rightPtr > leftPtr && theArray[rightPtr] >= pivot)

rightPtr--;

//當(dāng)leftPtr標(biāo)記大于等于right標(biāo)記的時候結(jié)束外層循環(huán)题篷,否則交換兩個標(biāo)記的數(shù)據(jù)項

if (leftPtr >= rightPtr)

break;

else

swap(leftPtr, rightPtr);

}

swap(leftPtr,right); //最后將當(dāng)前樞紐數(shù)值放入對應(yīng)的排序位置

return leftPtr;

}

/**

* 交換數(shù)據(jù)方法

*/

public void swap(int dex1, int dex2) {

long temp = theArray[dex1];

theArray[dex1] = theArray[dex2];

theArray[dex2] = temp;

}

/***快速排序的方法*/

public void recQuickSort(int left, int right) {

if (right - left <= 0) //這里是遞歸的基值條件,當(dāng)只有一個數(shù)據(jù)項的時候結(jié)束遞歸

return;

else {

long pivot = theArray[right]; //選擇最右邊的數(shù)據(jù)作為劃分的樞紐數(shù)據(jù)

int partition = partitionIt(left, right, pivot); //調(diào)用劃分的算法

//然后將劃分好的兩部分利用遞歸的思想進行再次劃分排序

recQuickSort(left, partition - 1);

recQuickSort(partition + 1, right);

}

}

}

下圖顯示了快速排序的過程

上面就是希爾排序算法和快速排序算法的所有內(nèi)容

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厅目,一起剝皮案震驚了整個濱河市番枚,隨后出現(xiàn)的幾起案子法严,更是在濱河造成了極大的恐慌,老刑警劉巖葫笼,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件深啤,死亡現(xiàn)場離奇詭異,居然都是意外死亡路星,警方通過查閱死者的電腦和手機溯街,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洋丐,“玉大人呈昔,你說我怎么就攤上這事∮丫” “怎么了堤尾?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長迁客。 經(jīng)常有香客問我哀峻,道長,這世上最難降的妖魔是什么哲泊? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任剩蟀,我火速辦了婚禮,結(jié)果婚禮上切威,老公的妹妹穿的比我還像新娘育特。我一直安慰自己,他們只是感情好先朦,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布缰冤。 她就那樣靜靜地躺著,像睡著了一般喳魏。 火紅的嫁衣襯著肌膚如雪棉浸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天刺彩,我揣著相機與錄音迷郑,去河邊找鬼。 笑死创倔,一個胖子當(dāng)著我的面吹牛嗡害,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畦攘,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼霸妹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了知押?” 一聲冷哼從身側(cè)響起叹螟,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鹃骂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后罢绽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體偎漫,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年有缆,在試婚紗的時候發(fā)現(xiàn)自己被綠了象踊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡棚壁,死狀恐怖杯矩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袖外,我是刑警寧澤史隆,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站曼验,受9級特大地震影響泌射,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鬓照,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一熔酷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧豺裆,春花似錦拒秘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔑歌,卻和暖如春羹应,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背次屠。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工园匹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人帅矗。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓偎肃,卻偏偏與公主長得像煞烫,于是被迫代替她去往敵國和親浑此。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 數(shù)據(jù)結(jié)構(gòu) Java中的數(shù)組有差不多一樣的語法滞详。只是java中處理8種基本類型凛俱,數(shù)組也是作為對象處理的紊馏,所以創(chuàng)建對...
    趙宇_阿特奇閱讀 702評論 0 0
  • 【程序1】 題目:古典問題:有一對兔子,從出生后第3個月起每個月都生一對兔子蒲犬,小兔子長到第三個月后每個月又生一對兔...
    開心的鑼鼓閱讀 3,310評論 0 9
  • 已經(jīng)用了很久了原叮,效果還是挺明顯的赫编,痘痘都淡化了,現(xiàn)在感覺皮膚變好多了奋隶,痘印很明顯的在變淡擂送,有些小的痘印已經(jīng)消失了。
    大大手掌閱讀 428評論 0 0
  • “完治著急的四處尋找,想起莉香一直想到自己的故鄉(xiāng)愛媛縣境氢,便匆匆趕回去蟀拷,最后在學(xué)校的柱子上,發(fā)現(xiàn)自己從前刻的名字旁...
    45度向陽閱讀 1,036評論 0 3
  • 我現(xiàn)在懷了孕萍聊,根本沒有辦法照顧潼曦问芬。再說我婆婆那里也不好交代。 孩子又不是我一個人的寿桨,難道要我一個人拉扯嗎愈诚? 林大...
    漫花燦爛時閱讀 363評論 0 0