一、隊列的特點
先進先出
隊列的應用
1. 一般的隊列
用鏈表或動態數組和指向隊列頭部的索引實現,隊列應支持兩種操作:入隊和出隊,具體看隊列
缺點:使用固定大小數組時,會造成空間浪費
當刪掉隊首元素後,頭指針後移,有一個空位無法使用。
解決方法:使用循環隊列
2. 優先隊列
優先隊列給每個元素增加了一個優先級屬性,優先級大的元素在前面,具體實現看優先級隊列
3. 循環隊列
使用固定大小的數組和兩個指針指示起始位置和終止位置,重用被浪費的存儲。
- 頭指針在前
- 頭指針在後
二、廣度優先搜索(DFS)
1. BFS的特點
(1)每一層的節點齊頭並進,像是面一樣往前走,所以在某一層找到的目標就是最短路徑。
(2)BFS的空間複雜度比DFS高,對於DFS空間複雜度就是遞歸堆棧,最壞情況下頂多就是樹的高度,也就是O(logN);對於BFS存儲每一層的所有節點,最壞情況下空間複雜度是樹的最底層節點的數量N/2,即O(N)。
// 模板
function BFS(root, target) {
// 定義隊列,存入根節點
let queue = [root];
// 每一層到根節點的距離
let step = 0;
// 使用哈西表防止重複訪問同一個節點
let hash = new Set();
hash.set(root);
// 隊列不爲空就說明沒有遍歷完
while(queue.length) {
// 深度加一
step += 1;
// 當前層節點的數量
let size = queue.length;
// 循環遍歷當前層每個節點
for(let i = 0; i < size; i++) {
// 提取第一個節點
let cur = queue.shift();
// 找到目標節點,返回距離
if(cur == target) return step;
// 保存這個節點對應的每個子節點
for(找到每個子節點node && !hash.get(node)) {
queue.push(node);
hash.set(node);
}
}
}
// 沒有目標節點
return false;
}
力扣200:島嶼數量
用矩陣表示的哈西表
var Node = function(i, j) {
this.i = i;
this.j = j;
}
var numIslands = function(grid) {
const row = grid.length;
if(!row) return 0;
const col = grid[0].length;
let queue = [];
let count = 0;
// 用矩陣表示訪問過的哈西表,一定要完整定義矩陣
let hash = new Array(row);
for(let i = 0; i < row; i++) {
hash[i] = new Array(col).fill(false);
}
// 定義每個節點的訪問的四個方向
let direction = [[-1,0], [0,-1], [1,0], [0,1]];
// 遍歷矩陣的每個格子
for(let i = 0; i < row; i++) {
for(let j = 0; j < col; j++) {
// 遇到爲1且未訪問過的就找它的連通區域,且標記爲已訪問
if(grid[i][j] == 1 && !hash[i][j]) {
// 島嶼數加1
count += 1;
queue.push(new Node(i, j));
hash[i][j] = true;
while(queue.length) {
let node = queue.shift();
for(item of direction) {
let new_i = node.i + item[0];
let new_j = node.j + item[1];
// 不越界、節點爲1、沒有被訪問過就加入隊列
if(new_i>=0 &&new_i<row && new_j>=0 && new_j<col && grid[new_i][new_j] == 1 && !hash[new_i][new_j]) {
queue.push(new Node(new_i, new_j));
hash[new_i][new_j] = true;
}
}
}
}
}
}
return count
};
注意:一定要完整定義矩陣,不然後面賦值賦錯。