數據結構——隊列與廣度優先遍歷

一、隊列的特點

先進先出
隊列的應用

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
};

注意:一定要完整定義矩陣,不然後面賦值賦錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章