生活随笔
收集整理的這篇文章主要介紹了
(十)数据结构之“堆”
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
數(shù)據(jù)結(jié)構(gòu)之“堆”
- 堆是什么?
- JS中的堆
- 堆的應(yīng)用
- 第K個最大元素
- LeetCode:215.數(shù)組中的第K個最大元素
- LeetCode:347.前K個高頻元素
- LeetCode:23.合并K個排序鏈表
- 思考題
堆是什么?
堆是一種特殊的完全二叉樹
所有的節(jié)點都大于等于(最大堆)或小于等于(最小堆)它的子節(jié)點
JS中的堆
JS中通常用數(shù)組表示堆
左側(cè)子節(jié)點的位置是2 * index + 1
右側(cè)子節(jié)點的位置是2 * index + 2
父節(jié)點位置是( index - 1 ) / 2
堆的應(yīng)用
堆能高效、快速地找出最大值和最小值,時間復(fù)雜度:O(1)
找出第K個最大(最小)元素
第K個最大元素
構(gòu)建一個最小堆,并將元素依次插入堆中
當堆的容量超過K,就刪除堆頂
插入結(jié)束后,堆頂就是第K個最大元素
實現(xiàn)步驟
在類里,生命一個數(shù)組,用來裝元素
主要方法:插入、刪除堆頂、獲取堆頂、獲取堆大小
插入
將值插入堆的底部,即數(shù)組的尾部
然后上移:將這個值和它的父節(jié)點進行交換,直到父節(jié)點小于等于這個插入的值
大小為k的堆中插入元素的時間復(fù)雜度為O(logk)
刪除堆頂
用數(shù)組尾部元素替換堆頂(直接刪除堆頂會破壞堆結(jié)構(gòu))
然后下移:將新堆頂和它的子節(jié)點進行交換,直到子節(jié)點大于等于這個新堆頂
大小為k的堆中刪除堆頂?shù)臅r間復(fù)雜度為O(logk)
獲取堆頂和堆的大小
獲取堆頂:返回數(shù)組的頭部
獲取堆的大小:返回數(shù)組的長度
class MinHeap {constructor() {this.heap
= [];}swap(i1
, i2
) {const temp
= this.heap
[i1
];this.heap
[i1
] = this.heap
[i2
];this.heap
[i2
] = temp
;}getParentIndex(i
) {return (i
- 1) >> 1;}getLeftIndex(i
) {return i
* 2 + 1;}getRightIndex(i
) {return i
* 2 + 2;}shiftUp(index
) {if (index
== 0) { return; }const parentIndex
= this.getParentIndex(index
);if (this.heap
[parentIndex
] > this.heap
[index
]) {this.swap(parentIndex
, index
);this.shiftUp(parentIndex
);}}shiftDown(index
) {const leftIndex
= this.getLeftIndex(index
);const rightIndex
= this.getRightIndex(index
);if (this.heap
[leftIndex
] < this.heap
[index
]) {this.swap(leftIndex
, index
);this.shiftDown(leftIndex
);}if (this.heap
[rightIndex
] < this.heap
[index
]) {this.swap(rightIndex
, index
);this.shiftDown(rightIndex
);}}insert(value
) {this.heap
.push(value
);this.shiftUp(this.heap
.length
- 1);}pop() {this.heap
[0] = this.heap
.pop();this.shiftDown(0);}peek() {return this.heap
[0];}size() {return this.heap
.length
;}
}const h
= new MinHeap();
h
.insert(3);
h
.insert(2);
h
.insert(1);
h
.pop();
LeetCode:215.數(shù)組中的第K個最大元素
解題思路
看到“第K個最大元素”
考慮選擇使用最小堆
解題步驟
構(gòu)建一個最小堆,并依次把數(shù)組的值插入堆中
當堆的容量超過K,就刪除堆頂
插入結(jié)束后,堆頂就是第K個最大元素
時間復(fù)雜度O(n * logk),空間復(fù)雜度O(k)
LeetCode:347.前K個高頻元素
法一:
時間復(fù)雜度O(n * logn)
法二
class MinHeap {constructor() {this.heap
= [];}swap(i1
, i2
) {const temp
= this.heap
[i1
];this.heap
[i1
] = this.heap
[i2
];this.heap
[i2
] = temp
;}getParentIndex(i
) {return (i
- 1) >> 1;}getLeftIndex(i
) {return i
* 2 + 1;}getRightIndex(i
) {return i
* 2 + 2;}shiftUp(index
) {if (index
== 0) { return; }const parentIndex
= this.getParentIndex(index
);if (this.heap
[parentIndex
] && this.heap
[parentIndex
].value
> this.heap
[index
].value
) {this.swap(parentIndex
, index
);this.shiftUp(parentIndex
);}}shiftDown(index
) {const leftIndex
= this.getLeftIndex(index
);const rightIndex
= this.getRightIndex(index
);if (this.heap
[leftIndex
] && this.heap
[leftIndex
].value
< this.heap
[index
].value
) {this.swap(leftIndex
, index
);this.shiftDown(leftIndex
);}if (this.heap
[rightIndex
] && this.heap
[rightIndex
].value
< this.heap
[index
].value
) {this.swap(rightIndex
, index
);this.shiftDown(rightIndex
);}}insert(value
) {this.heap
.push(value
);this.shiftUp(this.heap
.length
- 1);}pop() {this.heap
[0] = this.heap
.pop();this.shiftDown(0);}peek() {return this.heap
[0];}size() {return this.heap
.length
;}
}
時間O(n * logk),空間O(n)
LeetCode:23.合并K個排序鏈表
解題思路
新鏈表的下一個節(jié)點一定是k個鏈表頭中的最小節(jié)點
考慮選擇使用最小堆
解題步驟
構(gòu)建一個最小堆,并依次把鏈表頭插入堆中
彈出堆頂接到輸出鏈表,并將堆頂所在鏈表的新鏈表頭插入堆中
等堆元素全部彈出,合并工作就完成了
class MinHeap {constructor() {this.heap
= [];}swap(i1
, i2
) {const temp
= this.heap
[i1
];this.heap
[i1
] = this.heap
[i2
];this.heap
[i2
] = temp
;}getParentIndex(i
) {return (i
- 1) >> 1;}getLeftIndex(i
) {return i
* 2 + 1;}getRightIndex(i
) {return i
* 2 + 2;}shiftUp(index
) {if (index
== 0) { return; }const parentIndex
= this.getParentIndex(index
);if (this.heap
[parentIndex
] && this.heap
[parentIndex
].val
> this.heap
[index
].val
) {this.swap(parentIndex
, index
);this.shiftUp(parentIndex
);}}shiftDown(index
) {const leftIndex
= this.getLeftIndex(index
);const rightIndex
= this.getRightIndex(index
);if (this.heap
[leftIndex
] && this.heap
[leftIndex
].val
< this.heap
[index
].val
) {this.swap(leftIndex
, index
);this.shiftDown(leftIndex
);}if (this.heap
[rightIndex
] && this.heap
[rightIndex
].val
< this.heap
[index
].val
) {this.swap(rightIndex
, index
);this.shiftDown(rightIndex
);}}insert(value
) {this.heap
.push(value
);this.shiftUp(this.heap
.length
- 1);}pop() {if(this.size() === 1) return this.heap
.shift();const top
= this.heap
[0]this.heap
[0] = this.heap
.pop();this.shiftDown(0);return top
;}peek() {return this.heap
[0];}size() {return this.heap
.length
;}
}
時間復(fù)雜度O(n * logk),n是所有鏈表的節(jié)點數(shù)之和,k是排序鏈表數(shù),空間復(fù)雜度是O(k)
思考題
1、請用堆畫出一場比賽的運動員排名情況,無需 Coding。
2、在 LeetCode 找到一道堆的題目,并通過測試
總結(jié)
以上是生活随笔為你收集整理的(十)数据结构之“堆”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。