1. 程式人生 > >使用Tarjan演算法與並查集解決二叉樹節點間最近公共祖先的批量查詢問題

使用Tarjan演算法與並查集解決二叉樹節點間最近公共祖先的批量查詢問題

#include "Tree.h"
using namespace std;
//並查集結構
class DisjoinSets
{
public:
    DisjoinSets() {}
    void makeSets(Node* head)
    {
        fatherMap.clear();
        rankMap.clear();
        preOrderMake(head);
    }
    void setUnion(Node* a, Node* b);
    Node* findFather(Node* n);
private:
    map
<Node*, Node*>
fatherMap; map<Node*, int> rankMap; void preOrderMake(Node* head); }; void DisjoinSets::preOrderMake(Node* head) { if(head == nullptr) return; fatherMap[head] = head; rankMap[head] = 0; preOrderMake(head->left); preOrderMake(head->right); } Node* DisjoinSets::findFather(Node* n) { Node* father = fatherMap[n]; if
(father != n) father = findFather(father); fatherMap[n] = father; return father; } void DisjoinSets::setUnion(Node* a, Node* b) { if(a == nullptr || b == nullptr) return; Node* aFather = findFather(a); Node* bFather = findFather(b); if(aFather != bFather) { int
aRank = rankMap[aFather]; int bRank = rankMap[bFather]; if(aRank < bRank) { fatherMap[aFather] = bFather; } else if(aRank > bRank) { fatherMap[bFather] = aFather; } else { fatherMap[bFather] = aFather; rankMap[aFather] = aRank + 1; } } } struct Query { Node* o1; Node* o2; Query(Node* data1, Node* data2) : o1(data1), o2(data2) {} Query() : o1(nullptr), o2(nullptr) {} }; class Tarjan { public: Tarjan() { sets = new DisjoinSets(); } vector<Node*> query(Node* head , vector<Query*>& ques); private: map<Node*, list<Node*> > queryMap; map<Node*, list<int> > indexMap; map<Node*, Node*> ancestorMap; DisjoinSets* sets; void setQueries(vector<Query*> & ques, vector<Node*> & ans); void setAnswers(Node* head, vector<Node*> & ans); }; void Tarjan::setQueries(vector<Query*> & ques, vector<Node*> &ans) { Node* o1 = nullptr; Node* o2 = nullptr; for(int i = 0; i < ques.size(); ++i) { o1 = ques[i]->o1; o2 = ques[i]->o2; if(o1 == o2 || o1 == nullptr || o2 == nullptr) ans[i] = (o1 != nullptr ? o1 : o2); else { if(queryMap.find(o1) == queryMap.end()) { list<Node*> nlist; queryMap[o1] = nlist; list<int> ilist; indexMap[o1] = ilist; } if(queryMap.find(o2) == queryMap.end()) { list<Node*> nlist; queryMap[o2] = nlist; list<int> ilist; indexMap[o2] = ilist; } queryMap[o1].push_back(o2); indexMap[o1].push_back(i); queryMap[o2].push_back(o1); indexMap[o2].push_back(i); } } } void Tarjan::setAnswers(Node* head, vector<Node*> & ans) { if(head == nullptr) return; setAnswers(head->left, ans); sets->setUnion(head->left, head); ancestorMap[sets->findFather(head)] = head; setAnswers(head->right, ans); sets->setUnion(head->right, head); ancestorMap[sets->findFather(head)] = head; list<Node*> nList = queryMap[head]; list<int> iList = indexMap[head]; Node* node = nullptr; Node* nodefather = nullptr; int index = 0; while(!nList.empty()) { node = nList.front(); nList.pop_front(); index = iList.front(); iList.pop_front(); nodefather = sets->findFather(node); if(ancestorMap.find(nodefather) != ancestorMap.end()) ans[index] = ancestorMap[nodefather]; } } vector<Node*> Tarjan::query(Node* head, vector<Query*>& ques) { vector<Node*> ans(ques.size()); setQueries(ques, ans); sets->makeSets(head); setAnswers(head, ans); return ans; } int main() { Node* pNode0 = new Node(5); Node* pNode1 = new Node(3); Node* pNode2 = new Node(7); Node* pNode3 = new Node(2); Node* pNode4 = new Node(5); Node* pNode5 = new Node(6); Node* pNode6 = new Node(8); connectTree(pNode0, pNode1, pNode2); connectTree(pNode1, pNode3, pNode4); connectTree(pNode2, pNode5, pNode6); vector<Node*> ans; vector<Query*> ques; Query* q1 = new Query(pNode1, pNode3); Query* q2 = new Query(pNode3, pNode6); Query* q3 = new Query(pNode5, pNode6); ques.push_back(q1); ques.push_back(q2); ques.push_back(q3); Tarjan* tr = new Tarjan(); ans = tr->query(pNode0, ques); for(int i = 0; i < ans.size(); ++i) cout << ans[i]->value << endl; }

相關推薦

3.19 Tarjan演算法解決節點最近公共祖先批量查詢問題

【題目】:   如下的Node類是標準的二叉樹節點結構: 1 public class Node{ 2 public int value; 3 public Node left; 4 public Node right; 5 6 pu

使用Tarjan演算法解決節點最近公共祖先批量查詢問題

#include "Tree.h" using namespace std; //並查集結構 class DisjoinSets { public: DisjoinSets() {} void makeSets(Node* head) {

尋找中的最低公共祖先結點----LCA(Lowest Common Ancestor )問題(遞歸)

求解 mon etl 轉換成 right push_back 問題 off == 轉自 劍指Offer之 - 樹中兩個結點的最低公共祖先 題目: 求樹中兩個節點的最低公共祖先。 思路一: ——如果是二叉樹,而且是二叉搜索樹,那麽是可以找到公共節點的。 二叉搜索樹都是排序

3.20 節點的最大距離問題

距離 要求 最大 向上 出發 ron 老師 節點數 題目 【題目】:   從二叉樹的節點A出發,可以向上或者向下走,但沿途的節點只能經過一次,當到達節點B時,路徑上的節點數叫做A到B的距離   比如,下圖所示的二叉樹,節點4和節點2的距離為2,節點5和節點6的距離為5,給定

節點的最大距離

題目: 從二叉樹的節點A出發,可以向上或者向下走,但沿途的節點只能經過一次,當到達節點B時,路徑上的節點數叫作A 到B的距離。 比如,上圖所示的二叉樹,節點4和節點2的距離2,節點5和節點6的距離為5。給定一顆二叉樹的頭結點head求整棵樹上節點間的最大

【LCA】Tarjan離線演算法+dfs)模板

vector <int> Q[N]; int Find(int x) { if(x != fa[x]) return fa[x] = Find(fa[x]); return x; } void Union(int x, int y

Restructuring Company和Almost Union-Find 的區間合的刪除

whether who cfa elong cal proc rod question mine Restructuring Company Even the most successful company can go through a crisis period

最小生成樹問題(解決

pan font 距離 輸入 nbsp flag -o return quest 傳統的Prim算法或者是Kruskal算法求最小生成樹時,要先把圖創建出來,就比較麻煩。 如果用並查集來解決,依次選取權值最小的邊,判斷它們是否在一個並查集內,

wenbao(關於成環聯通)

scn ont unicom audio ios ems Go == bool 1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 c

wenbao

ima string 不斷學習 mage print \n %s ret ble 並查集: 1 int Find(int x){ 2 if(T[x] == -1) return x; 3 int xx = T[x]; 4

。洛谷P3378&P3367

c代碼 clas name 路徑壓縮 oid push tor return col 晚上A了一堆板子題我太弱了!堆:洛谷P3378AC代碼:(STL // luogu-judger-enable-o2 #include<iostream> #include&

HUD 3038 帶權 解決區間和矛盾問題

How Many Answers Are Wrong TT and FF are ... friends. Uh... very very good friends -________-b  FF is a bad boy, he is always wooing TT to play

HDU 1272 解決無向圖迴路

小希的迷宮 上次Gardon的迷宮城堡小希玩了很久(見Problem B),現在她也想設計一個迷宮讓Gardon來走。但是她設計迷宮的思路不一樣,首先她認為所有的通道都應該是雙向連通的,就是說如果有一個通道連通了房間A和B,那麼既可以通過它從房間A走到房間B,也可以通過它從房間B走到房間A,為了

(Java資料結構和演算法)最小生成樹---Kruskal演算法

該文章利用prime演算法求得連通圖的最小生成樹對應的邊權最小和,prime演算法是從頂點的角度思考和解決問題。本文介紹的Kruskal演算法將從邊的角度考慮並解決問題,利用了並查集方便地解決了最小生成樹的問題。 本文參考博文 //並查集 class UnionSameSet{

Wannafly挑戰賽14 C-可達性(tarjan縮點+)

思路來源 俊賢大佬 題解 tarjan縮點為無環圖, 每個強連通分量內的點排個序,取出標號最小的那個。 然後我們掃描等價的新圖。   若u和v在新圖裡面不是一個點,即來自不同的連通分量,//這句表達的思想很重要,網路流裡也有應用 且有邊u->v,

演算法

class UnionFind { Integer[] arr; public UnionFind(int size) { this.arr = new Integer[size]; for (int i = 1; i < arr.len

算到懷疑人生!如何用解決朋友圈個數問題?

作者 |  channingbreeze責編 | 郭芮 小史是一個應屆生,雖然學的是電子專業,但是自己業餘時間看了很多網際網路與程式設計方面的書,一心想進BAT網際網路公司。 今天小史去了一家社交小巨頭公司面試了。 面試現場

【圖解演算法 —— 聯合查詢演算法

WIKIWIKI 告訴我 —— 何為並查集 在電腦科學中,並查集(Union-Find)是一種樹型的資料結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題。 並查集存在兩個操作(1.union 聯合 2.find 查詢) 和一個需

演算法 C語言實現3

標頭檔案 UnionFind3.h #ifndef UNIONFIND3_H_INCLUDED #define UNIONFIND3_H_INCLUDED #include "stdlib.h" #include "ASSERT.h" typedef stru

最小生成樹------克魯斯卡爾演算法、sort)

1.並查集 用法:一個方便歸類的演算法。。。 將一個複雜的圖轉換成一個公共父節點的圖(如圖所示) 具體程式碼: ​ int find(int x) //並查集 { int r=x,i=x,temp; if (tree[r]==r) return