摘要:通常情況下,快速排序的時(shí)間復(fù)雜度為,但在最壞情況下它的時(shí)間復(fù)雜度會(huì)退化至,不過我們可以通過對(duì)輸入數(shù)組進(jìn)行隨機(jī)化打亂元素的排列順序來避免最壞情況的發(fā)生。
寫在最前面
導(dǎo)師貪腐出逃美國(guó),兩年未歸,可憐了我。拿了小米和美團(tuán)的offer,要被延期,offer失效,工作重新找。把準(zhǔn)備過程紀(jì)錄下來,共勉。
冒泡算法最初級(jí)
public void bubbleSort(int[] a){ int len = a.length; for(int i = 0; i < len; i++){ for(int j = 1; j < len; j++){ if(a[j - 1] > a[j]){ int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } } }
小優(yōu)化
public void bubbleSort(int[] a){ int len = a.length; for(int i = 0; i < len; i++){ for(int j = 1; j < len - i; j++){ if(a[j - 1] > a[j]){ int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } } }
大優(yōu)化,一次冒泡過程沒有交換,直接退出排序
public void bubbleSort(int[] a){ int len = a.length; boolean flag = true; while(flag){ flag = false; for(int j = 0; j < len - 1; j++){ if(a[j] > a[j + 1]){ int temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; flag = true; } } } }快速排序
快速排序是目前應(yīng)用最廣泛的排序算法之一,它是一般場(chǎng)景中大規(guī)模數(shù)據(jù)排序的首選,它的實(shí)際性能要好于歸并排序。通常情況下,快速排序的時(shí)間復(fù)雜度為O(nlogn),但在最壞情況下它的時(shí)間復(fù)雜度會(huì)退化至O(n^2),不過我們可以通過對(duì)輸入數(shù)組進(jìn)行“隨機(jī)化”(打亂元素的排列順序)來避免最壞情況的發(fā)生。除了實(shí)際執(zhí)行性能好,快速排序的另一個(gè)優(yōu)勢(shì)是它能夠?qū)崿F(xiàn)“原地排序”,也就是說它幾乎不需要額外的空間來輔助排序。
public static void quickSort(int[] a){ qSort(a, 0, a.length - 1); } private static void qSort(int[] a, int low, int high){ if(low < high){ int pivot = partition(a, low, high); qSort(a, low, pivot - 1); qSort(a, pivot + 1, high); } } private static void partition(int[] a, int low, int high){ int pivotValue = a[low]; while(low < high){ while(low < high && a[high] >= pivotValue){ high--; } a[low] = a[high]; while(low < high && a[low] <= pivotValue){ low++; } a[high] = a[low]; } a[low] = pivotValue; return low; }
穩(wěn)定性的概念并不復(fù)雜,它只表示兩個(gè)值相同的元素在排序前后是否有位置變化。如果前后位置變化,則排序算法是不穩(wěn)定的,否則是穩(wěn)定的。穩(wěn)定性的定義符合常理,兩個(gè)值相同的元素?zé)o需再次交換位置,交換位置是做了一次無用功。
兩個(gè)循環(huán)在進(jìn)行元素比較時(shí),分別用了小于和大于操作(也可以改用小于等于和大于等于,但是對(duì)性能沒有影響)。這就意味著如果出現(xiàn)和pivot值相同的元素,它都會(huì)被作為交換對(duì)象而移動(dòng)到pivot的前面或者后面,這就出現(xiàn)了值相同的元素會(huì)交換順序的問題,因而是不穩(wěn)定的。
本節(jié)參考 http://blog.csdn.net/yutianzu...
優(yōu)化選取樞軸,優(yōu)化不必要的交換
三數(shù)取中,即取三個(gè)關(guān)鍵字先進(jìn)行排序,將中間數(shù)作為樞軸, 一般是取左端、右端和中間三個(gè)數(shù), 也可以隨機(jī)選取。
修改partition算法
private static int partition(int[] a, int low, int high){ choosePivotValue(a, low, high); int pivotValue = a[low]; while(low < high){ while(low < high && a[high] > pivotValue){ high--; } //swap(a,low ,high);交換 //采用替換而不是交換的方式進(jìn)行操作 a[low] = a[high]; while(low < high && a[low] < pivotValue){ low++; } a[high] = a[low]; } a[low] = pivotValue; return low; } private static void swap(int[] a,int low,int high){ int temp = a[low]; a[low] = a[high]; a[high] = temp; } //使中間值處于a[low]的位置 private static void choosePivotValue(int[] a,int low,int high){ int mid = (low + high) / 2; if(a[low] > a[high]){ // 保證左端較小 swap(a, low, high); } if(a[mid] > a[high]){//保證中間較小 swap(a, mid, high); } if(a[mid] > a[low]){//保證中間較小 swap(a, low, mid); } }
優(yōu)化小數(shù)組時(shí)的排序方案
快速排序適用于非常大的數(shù)組的解決辦法, 那么相反的情況,如果數(shù)組非常小,其實(shí)快速排序反而不如直接插入排序來得更好(直接插入是簡(jiǎn)單排序中性能最好的)。其原因在于快速排序用到了遞歸操作,在大量數(shù)據(jù)排序時(shí),這點(diǎn)性能影響相對(duì)于它的整體算法優(yōu)勢(shì)是可以忽略的,但如果數(shù)組只有幾個(gè)記錄需要排序時(shí),這就成了大材小用,因此我們需要改進(jìn)一下 qSort函數(shù)。
public static void qSort(int[] a, int low, int high){ if((high - low) > MAX_LENGTH){ int pivot = partition(a, low, high); qSort(a, low, pivot - 1); qSort(a, pivot + 1, high); }else{ insertSort(a); } } private static void insertSort(int[] a){ for(int i = 1; i < a.length; i++){ int key = a[i]; int j = i - 1; while(j >= 0 && a[j] > key){ a[j + 1] = a[j]; } a[j + 1] = key; } }
優(yōu)化遞歸操作
遞歸對(duì)性能是有一定影響的, qSort 函數(shù)在其尾部有兩次遞歸操作。
如果待排序的序列劃分極端不平衡,遞歸深度將趨近與N ,而不是平衡時(shí)的 logN,就不僅僅是速度快慢的問題了,棧的大小是很有限的,每次遞歸調(diào)用都會(huì)耗費(fèi)一定的空間 ,函數(shù)的參數(shù)越多,每次遞歸耗費(fèi)的空間也越多。如果能減少遞歸,將會(huì)提高性能。我們對(duì) qSort 實(shí)施尾遞歸優(yōu)化。
public static void qSort(int[] a, int low, int high){ if((high - low) > MAX_LENGTH){ while(low < high){ int pivot = partition(a, low, high); qSort(a, low, pivot - 1); low = pivot + 1; } }else{ insertSort(a); } }
當(dāng)我們將 if 改成 while 后,因?yàn)榈谝淮芜f歸以后,變量low就沒有用處了,所以可以將pivot+1 賦值給low,再循環(huán)后,來一次 partition(arr,low,high)時(shí),其效果等同于“qSort(arr, pivot+1, high);”。結(jié)果相同,但因采用迭代而不是遞歸的方法可以縮減堆棧深度,從而提高了整體性能。
歸并排序本節(jié)參考 http://blog.csdn.net/scgaligu...
public static void sort(int[] a, int low, int high){ int mid = (low + high) / 2; sort(a, low, mid); sort(a, mid + 1, high); merge(a, low, mid, high); } private static void merge(int[] a, int low, int mid, int high){ int i = low; int j = mid + 1; int k = 0; int[] temp = new int[high - low + 1]; while(i <= mid && j <= high){ if(a[i] < a[j]){ temp[k++] = a[i++]; }else{ temp[k++] = a[j++]; } } while(i <= mid){ temp[k++] = a[i++]; } while(j <= high){ temp[k++] = a[j++]; } for(k = 0; k < temp.length; k++){ a[low + k] = temp[k]; } }選擇排序
public static void choseSort(int[] a){ for(int i = 0; i < a.length; i++){ int lowIndex = i; for(int j = i; j < a.length; j++){ if(a[j] < a[lowIndex]){ lowIndex = j; } } int temp = a[i]; a[i] = a[lowIndex]; a[lowIndex] = temp; } }插入排序
public static void insertSort(int[] a){ for(int i = 1; i < a.length; i++){ int j = i - 1; int key = a[i]; while(j >= 0 && a[j] > key){ a[j + 1] = a[j]; j--; } a[j + 1] = key; } }
本文參考 http://blog.csdn.net/xsf50717...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/70125.html
摘要:一基礎(chǔ)接口的意義百度規(guī)范擴(kuò)展回調(diào)抽象類的意義想不想通過一線互聯(lián)網(wǎng)公司面試文檔整理為電子書掘金簡(jiǎn)介谷歌求職記我花了八個(gè)月準(zhǔn)備谷歌面試掘金原文鏈接翻譯者 【面試寶典】從對(duì)象深入分析 Java 中實(shí)例變量和類變量的區(qū)別 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必保留原出處為:http://www.54tianzhisheng.cn/... , 歡迎訪問我的站點(diǎn),閱讀更多有深度的文章。 實(shí)例變量 和 類變量...
摘要:面試官說那我問你一個(gè)哲學(xué)的問題,為什么有數(shù)據(jù)結(jié)構(gòu)這種東西哇,這是啥,巴拉巴拉扯了一通,大致就是物以類聚,人以群分,先人積累下來的經(jīng)驗(yàn),這些讓我們更方便處理數(shù)據(jù)啥的。 前因,沒有比摸魚有趣的事了 距離自己被外派(俗稱外包)出去,已經(jīng)過了快五個(gè)月,工作的話,很閑。人啊,一定保持好的習(xí)慣,懶惰是會(huì)上癮,日常摸魚,懷疑人生,我是誰,我在哪,我要干什么。 中午吃飯的時(shí)候,收到了boss直聘的一條...
摘要:作者重慶森林鏈接來源牛客網(wǎng)整個(gè)三月份通過牛客網(wǎng)和網(wǎng)友分享的經(jīng)驗(yàn)學(xué)到了很多東西,現(xiàn)在反饋一下我的面試經(jīng)歷,希望對(duì)同學(xué)們有幫助。個(gè)人情況大三本方向渣碩,經(jīng)過實(shí)驗(yàn)室學(xué)長(zhǎng)內(nèi)推,于三月底完成面試。校招是實(shí)力和運(yùn)氣的結(jié)合,缺一不可。 歡迎關(guān)注我的微信公眾號(hào):Java面試通關(guān)手冊(cè)(堅(jiān)持原創(chuàng),分享美文,分享各種Java學(xué)習(xí)資源,面試題,以及企業(yè)級(jí)Java實(shí)戰(zhàn)項(xiàng)目回復(fù)關(guān)鍵字免費(fèi)領(lǐng)取):showImg(h...
摘要:算法名稱描述優(yōu)點(diǎn)缺點(diǎn)標(biāo)記清除算法暫停除了線程以外的所有線程算法分為標(biāo)記和清除兩個(gè)階段首1 回顧我的時(shí)間線 在本文的開頭,先分享一下自己的春招經(jīng)歷吧: 各位掘友大家好,我是練習(xí)時(shí)長(zhǎng)快一年的Android小蔡雞,喜歡看源碼,逛掘金,寫技術(shù)文章...... 好了好,不開玩笑了OWO,今年春招投了許多簡(jiǎn)歷的,但是被撈的只有阿里,頭條和美團(tuán),一路下來挺不容易的. 個(gè)人認(rèn)為在春招中運(yùn)氣>性格>三觀>技術(shù)...
摘要:正確做法是給加索引,還有聯(lián)合索引,并不能避免全表掃描。 前言:有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以 反對(duì) 沒有幫助 舉報(bào)三連 有心的同學(xué)應(yīng)該會(huì)看到我這個(gè)noteBook下面的其它知識(shí),希望對(duì)你們有些許幫助。 本文地址 時(shí)間點(diǎn):2017-11 一個(gè)16年畢業(yè)生所經(jīng)歷的php面試 一、什么是面試 二、面試準(zhǔn)備 1. 問:什么時(shí)候開始準(zhǔn)備? 2. 問:怎么準(zhǔn)備? 三、面試...
閱讀 2899·2021-09-22 15:54
閱讀 1897·2019-08-30 15:53
閱讀 2247·2019-08-29 16:33
閱讀 1425·2019-08-29 12:29
閱讀 1396·2019-08-26 11:41
閱讀 2376·2019-08-26 11:34
閱讀 2962·2019-08-23 16:12
閱讀 1428·2019-08-23 15:56