每日編程題之排序算法

1. 例題

http://exercise.acmcoder.com/online/online_judge_ques?ques_id=4382&konwledgeId=169

作為國內(nèi)領(lǐng)先的酒店預(yù)訂平臺狭归,去哪兒網(wǎng)為了廣大用戶能住到更舒適的酒店,根據(jù)實際用戶的居住評價對各酒店進(jìn)行動態(tài)評級和排名廓握。去哪兒網(wǎng)會從酒店整體環(huán)境鸿市、客房舒適度、服務(wù)質(zhì)量徙硅、配套設(shè)施和交通情況5的方面進(jìn)行評價收集榜聂,并給與 1-5 星的評分(整數(shù))。現(xiàn)希望開發(fā)者編寫程序根據(jù)一定的規(guī)則對酒店進(jìn)行排序嗓蘑。規(guī)則如下:

1.優(yōu)先按照最低星數(shù)進(jìn)行排序须肆,最低星數(shù)高者居前。
2.在最低星數(shù)相同時桩皿,按照平均星數(shù)排序豌汇,平均星數(shù)高者居前。
3.如果最低星數(shù)和平均星數(shù)均相同泄隔,則序號(數(shù)據(jù)里出現(xiàn)的順序編號拒贱,從0開始)小者居前。

2. 相關(guān)知識點

2.1 排序算法

常見的穩(wěn)定排序

1. 冒泡排序
function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len - 1; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {        // 相鄰元素兩兩對比
                var temp = arr[j+1];        // 元素交換
                arr[j+1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}
2. 直接插入排序
function insertionSort(arr) {
    var len = arr.length;
    var preIndex, current;
    for (var i = 1; i < len; i++) {
        preIndex = i - 1;
        current = arr[i];
        while(preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex+1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex+1] = current;
    }
    return arr;
}
3. 計數(shù)排序
function countingSort(arr, maxValue) {
    var bucket = new Array(maxValue+1),
        sortedIndex = 0;
        arrLen = arr.length,
        bucketLen = maxValue + 1;

    for (var i = 0; i < arrLen; i++) {
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0;
        }
        bucket[arr[i]]++;
    }

    for (var j = 0; j < bucketLen; j++) {
        while(bucket[j] > 0) {
            arr[sortedIndex++] = j;
            bucket[j]--;
        }
    }

    return arr;
}
4. 歸并排序
function mergeSort(arr) {  // 采用自上而下的遞歸方法
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right)
{
    var result = [];

    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}
5. 基數(shù)排序
//LSD Radix Sort
var counter = [];
function radixSort(arr, maxDigit) {
    var mod = 10;
    var dev = 1;
    for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        for(var j = 0; j < arr.length; j++) {
            var bucket = parseInt((arr[j] % mod) / dev);
            if(counter[bucket]==null) {
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);
        }
        var pos = 0;
        for(var j = 0; j < counter.length; j++) {
            var value = null;
            if(counter[j]!=null) {
                while ((value = counter[j].shift()) != null) {
                      arr[pos++] = value;
                }
          }
        }
    }
    return arr;
}
6. 桶排序
function bucketSort(arr, bucketSize) {
    if (arr.length === 0) {
      return arr;
    }

    var i;
    var minValue = arr[0];
    var maxValue = arr[0];
    for (i = 1; i < arr.length; i++) {
      if (arr[i] < minValue) {
          minValue = arr[i];                // 輸入數(shù)據(jù)的最小值
      } else if (arr[i] > maxValue) {
          maxValue = arr[i];                // 輸入數(shù)據(jù)的最大值
      }
    }

    //桶的初始化
    var DEFAULT_BUCKET_SIZE = 5;            // 設(shè)置桶的默認(rèn)數(shù)量為5
    bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
    var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;   
    var buckets = new Array(bucketCount);
    for (i = 0; i < buckets.length; i++) {
        buckets[i] = [];
    }

    //利用映射函數(shù)將數(shù)據(jù)分配到各個桶中
    for (i = 0; i < arr.length; i++) {
        buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
    }

    arr.length = 0;
    for (i = 0; i < buckets.length; i++) {
        insertionSort(buckets[i]);                      // 對每個桶進(jìn)行排序佛嬉,這里使用了插入排序
        for (var j = 0; j < buckets[i].length; j++) {
            arr.push(buckets[i][j]);                      
        }
    }

    return arr;
}

不穩(wěn)定排序

1. 選擇排序
function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    for (var i = 0; i < len - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {     // 尋找最小的數(shù)
                minIndex = j;                 // 將最小數(shù)的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}
2. 快速排序
function quickSort(arr, left, right) {
    var len = arr.length,
        partitionIndex,
        left = typeof left != 'number' ? 0 : left,
        right = typeof right != 'number' ? len - 1 : right;

    if (left < right) {
        partitionIndex = partition(arr, left, right);
        quickSort(arr, left, partitionIndex-1);
        quickSort(arr, partitionIndex+1, right);
    }
    return arr;
}
function partition(arr, left ,right) {     // 分區(qū)操作
    var pivot = left,                      // 設(shè)定基準(zhǔn)值(pivot)
        index = pivot + 1;
    for (var i = index; i <= right; i++) {
        if (arr[i] < arr[pivot]) {
            swap(arr, i, index);
            index++;
        }        
    }
    swap(arr, pivot, index - 1);
    return index-1;
}
function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
functiion paritition2(arr, low, high) {
  let pivot = arr[low];
  while (low < high) {
    while (low < high && arr[high] > pivot) {
      --high;
    }
    arr[low] = arr[high];
    while (low < high && arr[low] <= pivot) {
      ++low;
    }
    arr[high] = arr[low];
  }
  arr[low] = pivot;
  return low;
}
function quickSort2(arr, low, high) {
  if (low < high) {
    let pivot = paritition2(arr, low, high);
    quickSort2(arr, low, pivot - 1);
    quickSort2(arr, pivot + 1, high);
  }
  return arr;
}
3. 希爾排序
function shellSort(arr) {
    var len = arr.length,
        temp,
        gap = 1;
    while(gap < len/3) {          //動態(tài)定義間隔序列
        gap =gap*3+1;
    }
    for (gap; gap > 0; gap = Math.floor(gap/3)) {
        for (var i = gap; i < len; i++) {
            temp = arr[i];
            for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
                arr[j+gap] = arr[j];
            }
            arr[j+gap] = temp;
        }
    }
    return arr;
}
4. 堆排序
var len;    // 因為聲明的多個函數(shù)都需要數(shù)據(jù)長度逻澳,所以把len設(shè)置成為全局變量
function buildMaxHeap(arr) {   // 建立大頂堆
    len = arr.length;
    for (var i = Math.floor(len/2); i >= 0; i--) {
        heapify(arr, i);
    }
}
function heapify(arr, i) {     // 堆調(diào)整
    var left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;

    if (left < len && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < len && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        swap(arr, i, largest);
        heapify(arr, largest);
    }
}
function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
function heapSort(arr) {
    buildMaxHeap(arr);

    for (var i = arr.length-1; i > 0; i--) {
        swap(arr, 0, i);
        len--;
        heapify(arr, 0);
    }
    return arr;
}

2.2 數(shù)組排序

array.sort()方法
\\升序
function compareNumbers(a, b) {
  return a - b;
}
\\降序
function compareNumbers(a, b) {
  return b - a;
}

因為ECMAscript規(guī)范對于瀏覽器實現(xiàn)sort()方法有此說法

The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order)

所以不同瀏覽器實現(xiàn)array.sort()的算法不一樣,array.sort()在各個瀏覽器的穩(wěn)定性


修改array.sort()后實現(xiàn)穩(wěn)定性的方法

通過記錄元素原位置j暖呕,當(dāng)對比到兩個相同的元素(a.i=b.i)時斜做,按照原始的位置排序。

Array.prototype.stableSort = function (fn) {
  // 用新數(shù)組記錄位置
  var newArr = this.map(function (i, j) { return {i:i, j:j}; });
  return newArr.sort(function (a, b) {
    result = fn(a.i, b.i);
    if (result === 0) {
      // 按原先元素位置排序湾揽,升序
      return a.j - b.j;
    }
    return result;
  }).map(function (i) { return i.i; });
};

3. 思路

輸入的分?jǐn)?shù)數(shù)據(jù)瓤逼,看作五個數(shù)組。此題可看作對五個數(shù)組進(jìn)行穩(wěn)定排序
1.取每個酒店5方面得到的最低分作為依據(jù)库物,遞減排序霸旗;
2.對于最低分相同的酒店,根據(jù)5方面平均分作為依據(jù)艳狐,遞減排序定硝。

4. 代碼

會根據(jù)學(xué)習(xí)水平持續(xù)優(yōu)化代碼~

var n=5,
    record=["4 4 5 3 4", "3 3 3 3 3", "5 4 4 3 5", "5 5 5 5 5", "5 2 4 3 4"],
    score=0,
    result='';
//升序
function orderAsc(a, b) {
  return a[0] - b[0];
}
//降序  
function orderDes(a,b){
return b[0][0]-a[0][0];
}
//計算平均值
function   computeAvg(record){
    var avg=0;
    for(var i=0;i<5;i++){
    avg+=record[i]
    }
    avg=avg/5;
    return avg;
}
for(var i=0;i<n;i++){
    record[i]=record[i].split(" ");
    record[i]=record[i].stableSort(orderAsc);
    record[i][5]=i;
}
    record=record.stableSort(orderDes);
for(var j=0;j<n-1;j++){
  if(record[j][0]==record[j+1][0]){
    record=record.stableSort(function(a,b){
    return computeAvg(b)-computeAvg(a);
    })
  }
}
for(var k=0;k<n;k++){
   result+=record[k][5]+' ';
}
console.log(result)

5. 資料

Array.prototype.sort()
聊聊前端排序的那些事
GitBook《十大經(jīng)典排序算法》JavaScript 實現(xiàn)
javascript 數(shù)組的穩(wěn)定性排序

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市毫目,隨后出現(xiàn)的幾起案子蔬啡,更是在濱河造成了極大的恐慌,老刑警劉巖镀虐,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箱蟆,死亡現(xiàn)場離奇詭異,居然都是意外死亡刮便,警方通過查閱死者的電腦和手機(jī)空猜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辈毯,你說我怎么就攤上這事坝疼。” “怎么了谆沃?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵钝凶,是天一觀的道長。 經(jīng)常有香客問我唁影,道長耕陷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任据沈,我火速辦了婚禮哟沫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锌介。我一直安慰自己嗜诀,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布孔祸。 她就那樣靜靜地躺著裹虫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪融击。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天雳窟,我揣著相機(jī)與錄音尊浪,去河邊找鬼。 笑死封救,一個胖子當(dāng)著我的面吹牛拇涤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播誉结,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鹅士,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惩坑?” 一聲冷哼從身側(cè)響起掉盅,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎以舒,沒想到半個月后趾痘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蔓钟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年永票,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡侣集,死狀恐怖键俱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情世分,我是刑警寧澤编振,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站罚攀,受9級特大地震影響党觅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斋泄,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一杯瞻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炫掐,春花似錦魁莉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至痹束,卻和暖如春检疫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祷嘶。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工屎媳, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人论巍。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓烛谊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嘉汰。 傳聞我的和親對象是個殘疾皇子丹禀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

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