一些排序算法

摘自wiki和http://bubkoo.com/2014/01/17/sort-algorithm/archives/
什么是算法
https://zh.wikipedia.org/zh-hans/%E7%AE%97%E6%B3%95
排序演示 https://visualgo.net/zh/sorting
以下是高德納在他的著作《計算機(jī)程序設(shè)計藝術(shù)》里對算法的特征歸納:
輸入:一個算法必須有零個或以上輸入量擎淤。
輸出:一個算法應(yīng)有一個或以上輸出量险绘,輸出量是算法計算的結(jié)果。
明確性:算法的描述必須無歧義劈榨,以保證算法的實(shí)際執(zhí)行結(jié)果是精確地匹配要求或期望,通常要求實(shí)際運(yùn)行結(jié)果是確定的。
有限性:依據(jù)圖靈的定義衫樊,一個算法是能夠被任何圖靈完備系統(tǒng)模擬的一串運(yùn)算了罪,而圖靈機(jī)只有有限個狀態(tài)锭环、有限個輸入符號和有限個轉(zhuǎn)移函數(shù)(指令)。而一些定義更規(guī)定算法必須在有限個步驟內(nèi)完成任務(wù)泊藕。
有效性:又稱可行性田藐。能夠?qū)崿F(xiàn),算法中描述的操作都是可以通過已經(jīng)實(shí)現(xiàn)的基本運(yùn)算執(zhí)行有限次來實(shí)現(xiàn)

什么是數(shù)據(jù)結(jié)構(gòu)

就是數(shù)據(jù)的結(jié)構(gòu)吱七。
一般來說是這樣的:
我們要解決一個跟數(shù)據(jù)相關(guān)的問題
分析這個問題汽久,想出對應(yīng)的數(shù)據(jù)結(jié)構(gòu)
分析數(shù)據(jù)結(jié)構(gòu),想出算法
數(shù)據(jù)結(jié)構(gòu)和算法是互相依存踊餐、不可分開的
你學(xué)習(xí)完排序算法景醇,就能了解常見的數(shù)據(jù)結(jié)構(gòu)
大分類
分治法:把一個問題分區(qū)成互相獨(dú)立的多個部分分別求解的思路。這種求解思路帶來的好處之一是便于進(jìn)行并行計算吝岭。
動態(tài)規(guī)劃法:當(dāng)問題的整體最優(yōu)解就是由局部最優(yōu)解組成的時候三痰,經(jīng)常采用的一種方法。
貪婪算法:常見的近似求解思路窜管。當(dāng)問題的整體最優(yōu)解不是(或無法證明是)由局部最優(yōu)解組成散劫,且對解的最優(yōu)性沒有要求的時候,可以采用的一種方法幕帆。
線性規(guī)劃法:見詞條获搏。
簡并法:把一個問題通過邏輯或數(shù)學(xué)推理,簡化成與之等價或者近似的失乾、相對簡單的模型常熙,進(jìn)而求解的方法。
我們前端主要使用分治法——分而治之碱茁。

快速排序
快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分為兩個子序列(sub-lists)裸卫。
步驟為:
從數(shù)列中挑出一個元素,稱為"基準(zhǔn)"(pivot)纽竣,
重新排序數(shù)列墓贿,所有比基準(zhǔn)值小的元素擺放在基準(zhǔn)前面,所有比基準(zhǔn)值大的元素擺在基準(zhǔn)后面(相同的數(shù)可以到任何一邊)蜓氨。在這個分區(qū)結(jié)束之后聋袋,該基準(zhǔn)就處于數(shù)列的中間位置。這個稱為分區(qū)(partition)操作语盈。
遞歸地(recursively)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序舱馅。

遞歸到最底部時,數(shù)列的大小是零或一刀荒,也就是已經(jīng)排序好了代嗤。這個算法一定會結(jié)束棘钞,因?yàn)樵诿看蔚牡╥teration)中,它至少會把一個元素擺到它最后的位置去干毅。

Array.prototype.quick_sort = function() {
    var len = this.length;
    if (len <= 1)
        return this.slice(0);
    var left = [];
    var right = [];
    var mid = [this[0]];
    for (var i = 1; i < len; i++)
        if (this[i] < mid[0])
            left.push(this[i]);
        else
            right.push(this[i]);
    return left.quick_sort().concat(mid.concat(right.quick_sort()));
};

var arr = [5, 3, 7, 4, 1, 9, 8, 6, 2];
arr = arr.quick_sort();
for (i = 0; i < arr.length; i++)
    document.body.innerHTML += arr[i] + " ";
document.body.innerHTML += "<br>";

冒泡排序
冒泡排序算法的運(yùn)作如下:
比較相鄰的元素宜猜。如果第一個比第二個大,就交換他們兩個硝逢。
對每一對相鄰元素作同樣的工作姨拥,從開始第一對到結(jié)尾的最后一對。這步做完后渠鸽,最后的元素會是最大的數(shù)叫乌。
針對所有的元素重復(fù)以上的步驟,除了最后一個徽缚。
持續(xù)每次對越來越少的元素重復(fù)上面的步驟憨奸,直到?jīng)]有任何一對數(shù)字需要比較。

Array.prototype.quick_sort = function() {
    var len = this.length;
    if (len <= 1)
        return this.slice(0);
    var left = [];
    var right = [];
    var mid = [this[0]];
    for (var i = 1; i < len; i++)
        if (this[i] < mid[0])
            left.push(this[i]);
        else
            right.push(this[i]);
    return left.quick_sort().concat(mid.concat(right.quick_sort()));
};

var arr = [5, 3, 7, 4, 1, 9, 8, 6, 2];
arr = arr.quick_sort();
for (i = 0; i < arr.length; i++)
    document.body.innerHTML += arr[i] + " ";
document.body.innerHTML += "<br>";

插入排序
一般來說凿试,插入排序都采用in-place在數(shù)組上實(shí)現(xiàn)排宰。具體算法描述如下:
從第一個元素開始,該元素可以認(rèn)為已經(jīng)被排序
取出下一個元素那婉,在已經(jīng)排序的元素序列中從后向前掃描
如果該元素(已排序)大于新元素板甘,將該元素移到下一位置
重復(fù)步驟3,直到找到已排序的元素小于或者等于新元素的位置
將新元素插入到該位置后
重復(fù)步驟2~5

function insertionSort(array) {
  function swap(array, i, j) {
    var temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  var length = array.length,
      i,
      j;
  for (i = 1; i < length; i++) {
    for (j = i; j > 0; j--) {
      if (array[j - 1] > array[j]) {
        swap(array, j - 1, j);
      } else {
        break;
      }
    }
  }
  return array;
}

下面這種方式可以減少交換次數(shù):

function insertionSort(array) {
  var length = array.length,
    i,
    j,
    temp;
  for (i = 1; i < length; i++) {
    temp = array[i];
    for (j = i; j >= 0; j--) {
      if (array[j - 1] > temp) {
        array[j] = array[j - 1];
      } else {
        array[j] = temp;
        break;
      }
    }
  }
  return array;
}

桶排序
設(shè)置一個定量的數(shù)組當(dāng)作空桶子详炬。
尋訪序列盐类,并且把項(xiàng)目一個一個放到對應(yīng)的桶子去。
對每個不是空的桶子進(jìn)行排序痕寓。
從不是空的桶子里把項(xiàng)目再放回原來的序列中傲醉。
首先用最笨的方法,每一個桶只能放相同的數(shù)字呻率,最大桶的數(shù)量為數(shù)組中的正數(shù)最大值加上負(fù)數(shù)最小值的絕對值。

function bucketSort(array) {
    var bucket = [], // 正數(shù)桶
        negativeBucket = [], // 負(fù)數(shù)桶
        result = [],
        l = array.length,
        i,
        j,
        k,
        abs;
    // 入桶
    for (i = 0; i < l; i++) {
        if (array[i] < 0) {
            abs = Math.abs(array[i]);
            if (!negativeBucket[abs]) {
                negativeBucket[abs] = [];
            }
            negativeBucket[abs].push(array[i]);
        } else {
            if (!bucket[array[i]]) {
                bucket[array[i]] = [];
            }
            bucket[array[i]].push(array[i]);
        }
    }
    // 出桶
    l = negativeBucket.length;
    for (i = l - 1; i >= 0; i--) {
        if (negativeBucket[i]) {
            k = negativeBucket[i].length;
            for (j = 0; j < k; j++) {
                result.push(negativeBucket[i][j]);
            }
        }
    }
    l = bucket.length;
    for (i = 0; i < l; i++) {
        if (bucket[i]) {
            k = bucket[i].length;
            for (j = 0; j < k; j++) {
                result.push(bucket[i][j]);
            }
        }
    }
    return result;
}

下面這種方式就是文中舉例分析的那樣呻引,每個桶存放一定范圍的數(shù)字礼仗,用 step 參數(shù)來設(shè)置該范圍,取 step 為 1 就退化成前一種實(shí)現(xiàn)方式逻悠。關(guān)鍵部位代碼有注釋元践,慢慢看,邏輯稍微有點(diǎn)復(fù)雜童谒。

/*
* @array 將要排序的數(shù)組
*
* @step 劃分桶的步長单旁,比如 step = 5,表示每個桶存放的數(shù)字的范圍是 5饥伊,像 -4<sub>1象浑、0</sub>5蔫饰、6~11
*/
function bucketSort(array, step) {
    var result = [],
        bucket = [],
        bucketCount,
        l = array.length,
        i,
        j,
        k,
        s,
        max = array[0],
        min = array[0],
        temp;
    for (i = 1; i < l; i++) {
        if (array[i] > max) {
            max = array[i]
        }
        if (array[i] < min) {
            min = array[i];
        }
    }
    min = min - 1;
    bucketCount = Math.ceil((max - min) / step); // 需要桶的數(shù)量
    for (i = 0; i < l; i++) {
        temp = array[i];
        for (j = 0; j < bucketCount; j++) {
            if (temp > (min + step * j) && temp <= (min + step * (j + 1))) { // 判斷放入哪個桶
                if (!bucket[j]) {
                    bucket[j] = [];
                }
                // 通過插入排序?qū)?shù)字插入到桶中的合適位置
                s = bucket[j].length;
                if (s > 0) {
                    for (k = s - 1; k >= 0; k--) {
                        if (bucket[j][k] > temp) {
                            bucket[j][k + 1] = bucket[j][k];
                        } else {
                            break;
                        }
                    }
                    bucket[j][k + 1] = temp;
                } else {
                    bucket[j].push(temp);
                }
            }
        }
    }
    for (i = 0; i < bucketCount; i++) { // 循環(huán)取出桶中數(shù)據(jù)
        if (bucket[i]) {
            k = bucket[i].length;
            for (j = 0; j < k; j++) {
                result.push(bucket[i][j]);
            }
        }
    }
    return result;
}
QQ圖片20171101084653.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市愉豺,隨后出現(xiàn)的幾起案子篓吁,更是在濱河造成了極大的恐慌,老刑警劉巖蚪拦,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杖剪,死亡現(xiàn)場離奇詭異,居然都是意外死亡驰贷,警方通過查閱死者的電腦和手機(jī)盛嘿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來括袒,“玉大人次兆,你說我怎么就攤上這事∠浒荆” “怎么了类垦?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長城须。 經(jīng)常有香客問我蚤认,道長,這世上最難降的妖魔是什么糕伐? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任砰琢,我火速辦了婚禮,結(jié)果婚禮上良瞧,老公的妹妹穿的比我還像新娘陪汽。我一直安慰自己,他們只是感情好褥蚯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布挚冤。 她就那樣靜靜地躺著,像睡著了一般赞庶。 火紅的嫁衣襯著肌膚如雪训挡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天歧强,我揣著相機(jī)與錄音澜薄,去河邊找鬼。 笑死摊册,一個胖子當(dāng)著我的面吹牛肤京,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茅特,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼忘分,長吁一口氣:“原來是場噩夢啊……” “哼棋枕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起饭庞,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤戒悠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后舟山,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绸狐,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年累盗,在試婚紗的時候發(fā)現(xiàn)自己被綠了寒矿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡若债,死狀恐怖符相,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蠢琳,我是刑警寧澤啊终,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站傲须,受9級特大地震影響蓝牲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泰讽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一例衍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧已卸,春花似錦佛玄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至愧哟,卻和暖如春惑申,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翅雏。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留人芽,地道東北人望几。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像萤厅,于是被迫代替她去往敵國和親橄抹。 傳聞我的和親對象是個殘疾皇子靴迫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評論 2 349

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

  • 一、直接插入排序 直接插入排序(Insertion Sort)的基本思想是:每次將一個待排序的元素記錄楼誓,按其關(guān)鍵字...
    kevin16929閱讀 553評論 0 0
  • 概述排序有內(nèi)部排序和外部排序玉锌,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大疟羹,一次不能容納全部的...
    Luc_閱讀 2,259評論 0 35
  • 作者:快課網(wǎng)——Jay13原文地址:http://www.cricode.com/3212.html 排序算法可以...
    IT程序獅閱讀 3,738評論 2 78
  • 今天我們來總結(jié)一下經(jīng)典常用的排序算法主守。 排序算法可以分為內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序榄融,而...
    Tangmi_Up閱讀 1,443評論 1 15
  • 簡單排序 冒泡排序:循環(huán)遍歷左右比較参淫,較小者左移或較大者后移; 選擇排序:在未排序序列中找到最小者元素一次放到已排...
    王然Gondole閱讀 1,423評論 0 2