使用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