堆排序及C++實(shí)現(xiàn)PriorityQueue優(yōu)先級(jí)隊(duì)列

前言

堆一般是由數(shù)組實(shí)現(xiàn)的完全二叉樹(shù),堆的排序也屬于選擇排序,JAVA jdk中的PriorityQueue就是采用的小根堆實(shí)現(xiàn)的升序排序,因此要了解PriorityQueue就必須掌握堆的排序币他,這里就采用大根堆方式來(lái)實(shí)現(xiàn)默認(rèn)降序方式的PriorityQueue

一:堆排序

\color{red}{大根堆的概念:每個(gè)父節(jié)點(diǎn)的值都一定大于或等于子節(jié)點(diǎn) ; 小根堆:相反每個(gè)父節(jié)點(diǎn)的值都一定小于或等于子節(jié)點(diǎn) }

堆排序步驟:
1: 將無(wú)序數(shù)組構(gòu)造成一個(gè)大根堆(或小根堆), 大(小)根堆的構(gòu)造就是將最后一個(gè)非葉子結(jié)點(diǎn)到根節(jié)點(diǎn)進(jìn)行大小調(diào)整(結(jié)點(diǎn)的調(diào)整從上至下)以滿足大(小)根堆的概念

直接上圖(圖中采用的是大根堆方式),排序無(wú)序數(shù)組 12 2 6 30 17 5 22 18


大根堆調(diào)整.png

從圖中可以看出最后一個(gè)非葉子結(jié)點(diǎn)是30, 就需要依次調(diào)整 30 6 2 12結(jié)點(diǎn)

2:將堆根(數(shù)組首元素)與末尾元素交換, 即相當(dāng)于使數(shù)組末尾元素為最大, 再將除已經(jīng)排列出的最大的尾元素前的數(shù)組繼續(xù)大(小)根堆調(diào)整, 由于第一步已經(jīng)排列出大(小)根堆, 此時(shí)只需要直接從根節(jié)點(diǎn)開(kāi)始向下調(diào)整即可
替換并調(diào)整.png
3:代碼實(shí)現(xiàn)(大根堆實(shí)現(xiàn)升序)
class HeapSort {
public:
    /**
     * 堆排序
     * @param arrs
     * @param len
     */
    static void sort(int *arrs, int len) {
        for (int i = (len >> 1) - 1; i >= 0; --i) {
            siftDown(arrs, len, i);
        }
        for (int i = len - 1; i > 0 ; --i) {
            swap(arrs, 0, i);
            siftDown(arrs, i, 0);
        }
    }

    /**
     * 從上至下調(diào)整大根堆
     * @param arrs
     * @param len
     * @param index
     */
    static void siftDown(int *arrs, int len, int index) {
        while (index < len >> 1) {
            int maxChildIndex = (index << 1) + 1; //左右孩子中找出最大值的孩子的位置
            int rightChildIndex = maxChildIndex + 1;
            if (rightChildIndex < len && arrs[rightChildIndex] > arrs[maxChildIndex]) {
                maxChildIndex = rightChildIndex;
            }
            if (arrs[maxChildIndex] <= arrs[index]) return;
            swap(arrs, index, maxChildIndex);
            index = maxChildIndex;
        }
    }

    /**
     * 交換
     * @param arrs
     * @param l
     * @param r
     */
    static void swap(int *arrs, int l, int r) {
        int tmp = arrs[l];
        arrs[l] = arrs[r];
        arrs[r] = tmp;
    }
};

二:PriorityQueue降序?qū)崿F(xiàn)

PriorityQueue原理與堆排序類似,由于每次在隊(duì)列中加入元素的時(shí)候前面的元素已經(jīng)做好了大根堆調(diào)整,所以每次在隊(duì)列中加入元素的時(shí)候,從下至上與父結(jié)點(diǎn)比較,小于父節(jié)點(diǎn)不做處理, 大于父節(jié)點(diǎn)時(shí)與父節(jié)點(diǎn)替換,再與父點(diǎn)節(jié)比較,刪除節(jié)點(diǎn)時(shí)與堆排序的第2步一致

直接上代碼

template <class E>
struct Greater {
    constexpr bool operator() (const E &left, const E &right) const {
        return left > right;
    }
};

template <class E>
struct LessEqual {
    constexpr bool operator() (const E &left, const E &right) const {
        return left <= right;
    }
};

template <class E, class C = Greater<E> >
class PriorityQueue {
private:
    E *queue;
    //類似JDK中的Comparable
    C comparator;
    int len = 0;
    //初始數(shù)組大小
    int capacity = 11;
    /**
     * 擴(kuò)充數(shù)組
     * @param minCapacity
     */
    void grow();
    /**
     * 從下往上調(diào)整根堆
     * @param index
     * @param v
     */
    void siftUp(int index, const E &e);
    /**
     * 從上往下調(diào)整根堆
     * @param index
     * @param v
     */
    void siftDown(int index, const E &e);
public:
    PriorityQueue();
    PriorityQueue(int capacity);
    ~PriorityQueue();
    //隊(duì)列是否空
    bool isEmpty();
    /**
     * 優(yōu)先隊(duì)列中添加元素
     * @param e
     */
    void push(const E &e);
    /**
     * 彈出隊(duì)首元素
     * @return
     */
    E poll();
    //不彈出,查看首元素
    E peek();
};

//默認(rèn)大小11
template <class E, class C>
PriorityQueue<E, C>::PriorityQueue() : PriorityQueue(11) {
}

template <class E, class C>
PriorityQueue<E, C>::PriorityQueue(int capacity) {
    assert(capacity > 1);
    this->capacity = capacity;
    this->queue = (E*) malloc(sizeof(E) * capacity);
}

template <class E, class C>
PriorityQueue<E, C>::~PriorityQueue() {
    if (this->queue) {
        free(this->queue);
        this->queue = NULL;
    }
}

/**
 * 這里忽略擴(kuò)充數(shù)組后大小超過(guò)int最大值
 * @tparam E
 * @tparam C
 * @param minCapacity
 */
template <class E, class C>
void PriorityQueue<E, C>::grow() {
    //擴(kuò)充前的數(shù)組長(zhǎng)度超過(guò)64時(shí)擴(kuò)充1.5倍
    capacity = capacity + ((capacity < 64) ? (capacity + 2) : (capacity >> 1));
    queue = (E*) realloc(queue, sizeof(E) * capacity);
}

template <class E, class C>
void PriorityQueue<E, C>::siftUp(int index, const E &e) {
    int parentIndex;
    while (index > 0) {
        parentIndex = (index - 1) >> 1;//找出父節(jié)點(diǎn)的位置
        if (comparator(queue[parentIndex], e)) {//父節(jié)點(diǎn)大于該節(jié)點(diǎn),跳出循環(huán)
            break;
        }
        queue[index] = queue[parentIndex];
        index = parentIndex;
    }
    queue[index] = e;
}

template <class E, class C>
void PriorityQueue<E, C>::siftDown(int index, const E &e) {
    while (index < len >> 1) {
        int maxChildIndex = (index << 1) + 1;//左孩子與右孩子比較得出最大孩子的位置
        int rightChildIndex = maxChildIndex + 1;
        if (rightChildIndex < len && comparator(queue[rightChildIndex], queue[maxChildIndex])) {
            maxChildIndex = rightChildIndex;
        }
        if (!comparator(queue[maxChildIndex], e)) {
            break;
        }
        queue[index] = queue[maxChildIndex];
        index = maxChildIndex;
    }
    queue[index] = e;
}


template <class E, class C>
bool PriorityQueue<E, C>::isEmpty() {
    return len <= 0;
}

template <class E, class C>
void PriorityQueue<E, C>::push(const E &e) {
    if (this->len >= capacity) {
        grow();
    }
    siftUp(this->len, e);
    this->len++;
}

template <class E, class C>
E PriorityQueue<E, C>::poll() {
    assert(len > 0);
    E max = queue[0];
    this->len--;
    if (this->len > 0) {
        siftDown(0, queue[len]);
    }
    return max;
}

template <class E, class C>
E PriorityQueue<E, C>::peek() {
    assert(len > 0);
    return queue[0];
}
最后附上源碼https://github.com/youxiaochen/DataStructArrayLink
數(shù)據(jù)結(jié)構(gòu)看10次都不如自己動(dòng)手敲一次印象深,代碼中如有錯(cuò)誤歡迎指教

更多文章請(qǐng)關(guān)注:http://www.reibang.com/u/b1cff340957c

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子隔盛,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胖腾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瘪松,警方通過(guò)查閱死者的電腦和手機(jī)咸作,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宵睦,“玉大人记罚,你說(shuō)我怎么就攤上這事】呛浚” “怎么了桐智?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)烟馅。 經(jīng)常有香客問(wèn)我说庭,道長(zhǎng),這世上最難降的妖魔是什么郑趁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任刊驴,我火速辦了婚禮,結(jié)果婚禮上穿撮,老公的妹妹穿的比我還像新娘缺脉。我一直安慰自己,他們只是感情好悦穿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著业踢,像睡著了一般栗柒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上知举,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天瞬沦,我揣著相機(jī)與錄音,去河邊找鬼雇锡。 笑死逛钻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锰提。 我是一名探鬼主播曙痘,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼芳悲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了边坤?” 一聲冷哼從身側(cè)響起名扛,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茧痒,沒(méi)想到半個(gè)月后肮韧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旺订,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年弄企,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片区拳。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桩蓉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出劳闹,到底是詐尸還是另有隱情院究,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布本涕,位于F島的核電站业汰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏菩颖。R本人自食惡果不足惜样漆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晦闰。 院中可真熱鬧放祟,春花似錦、人聲如沸呻右。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)声滥。三九已至眉撵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間落塑,已是汗流浹背纽疟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憾赁,地道東北人污朽。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像龙考,于是被迫代替她去往敵國(guó)和親蟆肆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矾睦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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