成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

我理解的數(shù)據(jù)結(jié)構(gòu)(七)—— 堆和優(yōu)先隊(duì)列(Heap And PriorityQueue)

Simon / 3269人閱讀

摘要:我理解的數(shù)據(jù)結(jié)構(gòu)七堆和優(yōu)先隊(duì)列一堆堆的基礎(chǔ)堆也是一顆樹(shù)堆最為主流的一種實(shí)現(xiàn)方式二叉堆二叉堆是一顆完全二叉樹(shù)完全二叉樹(shù)完全二叉樹(shù)是效率很高的數(shù)據(jù)結(jié)構(gòu),完全二叉樹(shù)是由滿二叉樹(shù)而引出來(lái)的。

我理解的數(shù)據(jù)結(jié)構(gòu)(七)—— 堆和優(yōu)先隊(duì)列(Heap And PriorityQueue) 一、堆

1.堆的基礎(chǔ)

堆也是一顆樹(shù)

堆最為主流的一種實(shí)現(xiàn)方式:二叉堆

二叉堆是一顆完全二叉樹(shù)

2.完全二叉樹(shù)

完全二叉樹(shù)是效率很高的數(shù)據(jù)結(jié)構(gòu),完全二叉樹(shù)是由滿二叉樹(shù)而引出來(lái)的。對(duì)于深度為K的,有n個(gè)結(jié)點(diǎn)的二叉樹(shù),當(dāng)且僅當(dāng)其每一個(gè)結(jié)點(diǎn)都與深度為K的滿二叉樹(shù)中編號(hào)從1至n的結(jié)點(diǎn)一一對(duì)應(yīng)時(shí)稱之為完全二叉樹(shù)。
(通俗來(lái)說(shuō):完全二叉樹(shù)不一定是滿二叉樹(shù),當(dāng)一層已滿容納不下新的節(jié)點(diǎn)時(shí),新的一層從左至右來(lái)盛放新節(jié)點(diǎn),缺失的節(jié)點(diǎn)一定在右側(cè))

最大堆:堆中某個(gè)節(jié)點(diǎn)的值總是不大于其父節(jié)點(diǎn)的值(相應(yīng)的,可以定義最小堆)

3.用數(shù)組存儲(chǔ)二叉堆

4.基礎(chǔ)代碼實(shí)現(xiàn)

這里的ArrayNew是我之前實(shí)現(xiàn)的數(shù)組:數(shù)組代碼
public class Heap> {

    private ArrayNew data;

    public Heap(int capacity) {
        data = new ArrayNew<>(capacity);
    }

    public Heap() {
        data = new ArrayNew<>();
    }

    // 返回堆中的元素個(gè)數(shù)
    public int size() {
        return data.getSize();
    }

    // 堆中是否包含元素
    public boolean isEmpty() {
        return data.isEmpty();
    }

    // 父節(jié)點(diǎn)的索引
    private int parent(int index) {
        if (index == 0) {
            throw new IllegalArgumentException("index-0 doesn"t have parent");
        }
        return (index - 1) / 2;
    }

    // 左子節(jié)點(diǎn)的索引
    private int leftChild(int index) {
        return 2 * index + 1;
    }

    // 右子節(jié)點(diǎn)的索引
    private int rightChild(int index) {
        return 2 * index + 2;
    }

}

5.添加元素(sift up

步驟:

在最后一層的最后添加這個(gè)元素,如果是滿樹(shù),則在新的一層最左端添加

與其父節(jié)點(diǎn)做比較,如果父節(jié)點(diǎn)小于當(dāng)前元素的節(jié)點(diǎn),置換位置

以此類推,直到比較至根節(jié)點(diǎn)

// 添加元素
public void add(E e) {
    data.addLast(e);
    siftUp(data.getSize() - 1);
}

// 上浮
private void siftUp(int index) {

    // 添加的元素大于父節(jié)點(diǎn)的元素
    while (index > 0 && data.get(index).compareTo(data.get(parent(index))) > 0) {
        data.swap(index, parent(index));
        index = parent(index);
    }
}

6.取出元素(sift down

步驟:

最后一個(gè)節(jié)點(diǎn)與根節(jié)點(diǎn)交換,取出末尾節(jié)點(diǎn),這樣整體樹(shù)結(jié)構(gòu)不會(huì)改變,只是位置不對(duì)

根節(jié)點(diǎn)與子節(jié)點(diǎn)的元素做比較,如果比子節(jié)點(diǎn)的最大的節(jié)點(diǎn)元素小,則置換位置

以此類推,直至比子節(jié)點(diǎn)的元素都大

// 查看堆中的最大值
public E findMax() {
    if (data.isEmpty()) {
        throw new IllegalArgumentException("can"t find Max in empty heap");
    }

    return data.get(0);
}

// 取出堆中的最大值
public E extractMax() {
    E ret = data.get(0);

    data.swap(0, data.getSize() - 1);
    data.removeLast();
    siftDown(0);
    return ret;
}

// 下沉
private void siftDown(int index) {

    while (leftChild(index) < data.getSize()) { // 有子節(jié)點(diǎn)(左子節(jié)點(diǎn)沒(méi)有越界)

        int j = leftChild(index);

        // 有右子節(jié)點(diǎn),并且右節(jié)點(diǎn)元素大于左節(jié)點(diǎn)元素
        if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0) {
            j = j + 1;
        }

        // 此時(shí),data[j]就是左右子節(jié)點(diǎn)的最大節(jié)點(diǎn)值

        if (data.get(j).compareTo(data.get(index)) <= 0) {
            break;
        }

        data.swap(index, j);
        index = j;
    }
}

7.Heapify和replace

replace(取出堆中的最大元素,再放入一個(gè)新的元素)

實(shí)現(xiàn):可以先extractMaxadd,但是這樣會(huì)有兩次O(logn)操作

優(yōu)化:可以將堆頂元素替換以后再siftDown,這樣只有一次O(logn)操作

// 取出堆中的最大元素,并替換成元素e,重新siftDown
public E replace(E e) {
    E ret = data.get(0);
    data.set(0, e);
    siftDown(0);
    return ret;
}

heapify(將任意數(shù)組整理成堆的形狀)

實(shí)現(xiàn):將n個(gè)元素逐個(gè)插入到一個(gè)空堆中,算法復(fù)雜度是O(logn)

優(yōu)化:heapify(算法復(fù)雜度是O(n))

將任意一個(gè)數(shù)組看成完全二叉樹(shù)(盡管元素的位置不對(duì))

找到最后一個(gè)非葉子節(jié)點(diǎn)(最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn))

從最后一個(gè)非葉子節(jié)點(diǎn)倒著不斷的對(duì)每個(gè)節(jié)點(diǎn)siftDown就可以了

// heapify
public Heap(E[] arr) {
    data = new ArrayNew<>(arr);
    for (int i = parent(data.getSize() - 1); i > 0; i--) {
        siftDown(i);
    }
}

8. 復(fù)雜度分析

因?yàn)槎训娜〕龊吞砑訌?fù)雜度都是O(logn),所以堆的性能是很高的。
操作 時(shí)間復(fù)雜度
add O(logn)
extractMax O(logn)
二、優(yōu)先隊(duì)列

1.優(yōu)先隊(duì)列基礎(chǔ)

普通隊(duì)列:先進(jìn)先出,后進(jìn)后出

優(yōu)先隊(duì)列:出隊(duì)順序和入隊(duì)順序無(wú)關(guān),和優(yōu)先級(jí)有關(guān)

2.隊(duì)列接口

public interface Queue {
    int getSize();
    boolean isEmpty();
    void enqueue(E e);
    E dequeue();
    // 查看隊(duì)首元素
    E getFront();
}

3.基于堆的優(yōu)先隊(duì)列代碼實(shí)現(xiàn)

public class priorityQueue> implements Queue {

    Heap data;

    public priorityQueue() {
        data = new Heap<>();
    }

    @Override
    public int getSize() {
        return data.size();
    }

    @Override
    public boolean isEmpty() {
        return data.isEmpty();
    }

    @Override
    public void enqueue(E e) {
        data.add(e);
    }

    @Override
    public E dequeue() {
        return data.extractMax();
    }

    @Override
    public E getFront() {
        return data.findMax();
    }
}

4.LeetCode中有關(guān)優(yōu)先隊(duì)列的問(wèn)題

347. 前K個(gè)高頻元素

題目:347. 前K個(gè)高頻元素

描述:給定一個(gè)非空的整數(shù)數(shù)組,返回其中出現(xiàn)頻率前 k 高的元素。

例子:

示例 1:
輸入: nums = [1,1,1,2,2,3], k = 2
輸出: [1,2]

示例 2:
輸入: nums = [1], k = 1
輸出: [1]

解決代碼:

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

// 只需要在`Solution`這個(gè)類中引入所需要的類即可
// 所有的類都可以在之前的博客中找到
public class Solution {

    private class Freq implements Comparable {
        public int e, freq;

        public Freq(int e, int freq) {
            this.e = e;
            this.freq = freq;
        }

        @Override
        public int compareTo(Freq another) {
            if (this.freq < another.freq) {
                return 1;
            } else if (this.freq > another.freq) {
                return -1;
            } else {
                return 0;
            }
        }
    }

    public List topKFrequent(int[] nums, int k) {

        TreeMap map = new TreeMap<>();
        for (int num : nums) {
            if (map.containsKey(num)) {
                map.put(num, map.get(num) + 1);
            } else {
                map.put(num, 1);
            }
        }

        PriorityQueue pq = new PriorityQueue<>();
        for (int key : map.keySet()) {
            if (pq.getSize() < k) {
                pq.enqueue(new Freq(key, map.get(key)));
            } else if (map.get(key) > pq.getFront().freq) {
                pq.dequeue();
                pq.enqueue(new Freq(key, map.get(key)));
            }
        }

        ArrayList list = new ArrayList<>();
        while (!pq.isEmpty()) {
            list.add(pq.dequeue().e);
        }
        return list;
    }

}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71800.html

相關(guān)文章

  • 理解數(shù)據(jù)結(jié)構(gòu))—— 堆和優(yōu)先隊(duì)列Heap And PriorityQueue

    摘要:我理解的數(shù)據(jù)結(jié)構(gòu)七堆和優(yōu)先隊(duì)列一堆堆的基礎(chǔ)堆也是一顆樹(shù)堆最為主流的一種實(shí)現(xiàn)方式二叉堆二叉堆是一顆完全二叉樹(shù)完全二叉樹(shù)完全二叉樹(shù)是效率很高的數(shù)據(jù)結(jié)構(gòu),完全二叉樹(shù)是由滿二叉樹(shù)而引出來(lái)的。 我理解的數(shù)據(jù)結(jié)構(gòu)(七)—— 堆和優(yōu)先隊(duì)列(Heap And PriorityQueue) 一、堆 1.堆的基礎(chǔ) 堆也是一顆樹(shù) 堆最為主流的一種實(shí)現(xiàn)方式:二叉堆 二叉堆是一顆完全二叉樹(shù) 2.完全二叉樹(shù) ...

    I_Am 評(píng)論0 收藏0
  • PHP面試:說(shuō)下什么是堆和堆排序?

    摘要:一個(gè)常見(jiàn)的例子就是優(yōu)先隊(duì)列,還有排序算法之一的堆排序。另外我們還將學(xué)習(xí)堆排序,并將使用實(shí)現(xiàn)堆。堆排序在堆排序中,我們需要用給定的值構(gòu)建一個(gè)一個(gè)堆。偽代碼如下從上面的偽代碼可以看到,堆排序的第一步就是構(gòu)建一個(gè)堆。 堆是什么? 堆是基于樹(shù)抽象數(shù)據(jù)類型的一種特殊的數(shù)據(jù)結(jié)構(gòu),用于許多算法和數(shù)據(jù)結(jié)構(gòu)中。一個(gè)常見(jiàn)的例子就是優(yōu)先隊(duì)列,還有排序算法之一的堆排序。這篇文章我們將討論堆的屬性、不同類型的堆...

    twohappy 評(píng)論0 收藏0
  • PyTips 0x10 - Python 堆與優(yōu)先隊(duì)列

    摘要:項(xiàng)目地址中內(nèi)置的庫(kù)和分別提供了堆和優(yōu)先隊(duì)列結(jié)構(gòu),其中優(yōu)先隊(duì)列本身也是基于實(shí)現(xiàn)的,因此我們這次重點(diǎn)看一下。堆可以用于實(shí)現(xiàn)調(diào)度器例見(jiàn)之協(xié)程,更常用的是優(yōu)先隊(duì)列例如。 項(xiàng)目地址:https://git.io/pytips Python 中內(nèi)置的 heapq 庫(kù)和 queue 分別提供了堆和優(yōu)先隊(duì)列結(jié)構(gòu),其中優(yōu)先隊(duì)列 queue.PriorityQueue 本身也是基于 heapq 實(shí)現(xiàn)的,因...

    dreambei 評(píng)論0 收藏0
  • [Leetcode] Merge Two Sorted Lists Merge K Sorted L

    摘要:注意因?yàn)槎阎惺擎湵砉?jié)點(diǎn),我們?cè)诔跏蓟褧r(shí)還要新建一個(gè)的類。代碼初始化大小為的堆拿出堆頂元素將堆頂元素的下一個(gè)加入堆中 Merge Two Sorted Lists 最新更新請(qǐng)見(jiàn):https://yanjia.me/zh/2019/01/... Merge two sorted linked lists and return it as a new list. The new list...

    stefanieliang 評(píng)論0 收藏0
  • 堆和索引堆python實(shí)現(xiàn)

    摘要:堆分為大根堆和小根堆,大根堆是父節(jié)點(diǎn)大于左右子節(jié)點(diǎn),并且左右子樹(shù)也滿足該性質(zhì)的完全二叉樹(shù)。其中表示向下取整。則一直指向,一直指向,因?yàn)槲覀冊(cè)谡{(diào)整堆結(jié)構(gòu)中實(shí)際調(diào)整的是索引數(shù)組,而不會(huì)改變真實(shí)存放數(shù)據(jù)的數(shù)組。以上就是實(shí)現(xiàn)對(duì)和索引堆的具體方式。 堆是一棵完全二叉樹(shù)。堆分為大根堆和小根堆,大根堆是父節(jié)點(diǎn)大于左右子節(jié)點(diǎn),并且左右子樹(shù)也滿足該性質(zhì)的完全二叉樹(shù)。小根堆相反??梢岳枚褋?lái)實(shí)現(xiàn)優(yōu)先隊(duì)列。...

    寵來(lái)也 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<