树基础总结(算法导论)
2015-11-01 11:29
459 查看
0.树的存储结构
a.当孩子个数有限时(全部单列出来)
d.类似于并查集
1.树的遍历
a.前、中、后序遍历
2.树的应用
a.二叉查找树
思考:在构建二叉查找树之前,对输入数据进行洗牌,会不会更好。但是如果数据不是像例子中一次性给出,那么也就没办法对输入数据进行洗牌了。
b.红黑树
是一种二叉查找树,也是一种平衡树。典型的用途是实现关联数组(c++中的map,set ?)
节点数据结构如下:
1.节点非黑即红(对于分析没有实际意义)
2.根节点是黑色的(说不出来,但写插入时,很有用,情况四再次向上调整时有用,父亲节点是红色时,一定存在祖父节点的判定...模糊)
3.叶节点(空节点)是黑色的(为方便代码编写和算法实现)
4.红节点的子节点是黑色的(并不意味着每条路径上的节点都是黑红交替的)
5.对于每个节点,从该节点到其子孙叶节点(空节点)的所有路径上包含的黑节点数目是相同的
红黑树的平衡性讨论:
由条件5可知:因为从一点出发,任何一条路径到叶节点所经历的黑节点个数是相同的,所以一条路径上的红节点个数越多,路径也就越长
由条件4和上条推论可知:因为红节点的子节点一定是黑的,意味着两个红节点是不可能连续,所以红节点最多时,就是在每两个黑节点之间插上1个,所以红节点最多与黑节点个数相同
由上可推出:
最长路径是红黑交替出现长度为2n(n为黑节点个数)
最短路径是纯黑节点长度为n
最长路径最多是最短路径的两倍,这保证了这棵树的平衡性。(当然对比严格的平衡二叉树来说,平衡性肯定是要差些的)
红黑树的插入:(中心思想:插入新节点,不能破坏性质1~5,这样才能保证树的平衡)
写的很好:http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html
情况1:根节点为空,插入节点设为根节点,color设为黑
情况2:已经存在该节点,直接返回
情况3:父亲节点为黑,插入后,无需调整,直接返回
情况4:父亲节点为红,且叔叔节点也为红,插入后,将父亲节点设为黑,叔叔节点设为黑,祖父节点(父亲节点为红,则至少有祖父root为黑)设为红,将祖父节点作为新节点,再次向上调整
情况5:父亲节点为红,叔叔节点为黑,父亲节点为左(右)孩子,新节点也为左(右)孩子,右(左)单旋,原父亲节点站在了原祖父节点的位置上,原父亲节点转黑,原祖父节点转红
情况6:父亲节点为红,叔叔节点为黑,父亲节点为左(右)孩子,新节点为右(左)孩子,左(右)旋,各节点颜色不变。现在成了情况5,转情况5处理
红黑树的删除:(中心思想:删除某个节点,要保证黑节点个数不变,这样性质5才不会被破坏)
写的很好:http://blog.csdn.net/spch2008/article/details/9338923
最重要的一点,以下结构会破坏性质5,所以不会出现(盗图):
详细参看上述博客
红黑树代码:(仅插入部分,删除真的好麻烦!)
红黑树与严格的AVL树(高度平衡二叉树)(考研时数构考过)的比对:
转自:http://blog.csdn.net/klarclm/article/details/7780319
相对于AVL树而言,红黑树牺牲了严格的高度平衡的优越条件为 代价,红黑树能够以O(log n)的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决(参看插入操作)。当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。
当然,红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。
c.哈夫曼树(编码)
d.并查集
初始化,查根,合并代码如下
Kruscal最小生成树:
a.当孩子个数有限时(全部单列出来)
struct Tree { int data; Tree *ltree; Tree *rtree; };b.当孩子个数不定时(将孩子节点连在一起)
struct Node { int data; vector<int> child;//孩子节点的序号 }; vector<Node> tree;c.对于完全/满二叉树(可以利用,父亲节点序号i,左孩子2i,右孩子2i+1的性质)
vector<int> data;//data[0]不存储元素
d.类似于并查集
vector<Node> node;//整棵树的节点 node[childId]=fatherId;
1.树的遍历
a.前、中、后序遍历
struct Tree { int data; Tree *ltree; Tree *rtree; };b.广、深度遍历
//前序
void preTraversal(Tree *head)
{
if(head==NULL)
{
return;
}
cout<<head->data;
preTraversal(head->ltree);
preTraversal(head->rtree);
}
//中序
void preTraversal(Tree *head)
{
if(head==NULL)
{
return;
}
preTraversal(head->ltree);
cout<<head->data;
preTraversal(head->rtree);
}
//后序
void preTraversal(Tree *head)
{
if(head==NULL)
{
return;
}
preTraversal(head->ltree);
preTraversal(head->rtree);
cout<<head->data;
}
struct Tree { int data; vector<Tree*> chlid; }; //广度优先 void breadthTraversal(Tree *head) { queue<Tree*> q; q.push(head); while(!q.empty()) { Tree *temp=q.front(); q.pop(); cout<<temp->data; for(int i=0;i<temp->chlid.size();i++) { q.push(temp->chlid[i]); } } } //深度优先 void depthTraversal(Tree *head) { if(head==NULL) { return; } cout<<head->data; for(int i=0;i<head->chlid.size();i++) { depthTraversal(temp->chlid[i]); } }
2.树的应用
a.二叉查找树
#include<iostream> #include<stack> #include<queue> using namespace std; template<class Type> struct Node { Type cdata; Node *lchild; Node *rchild; Node(Type temp):cdata(temp),lchild(NULL),rchild(NULL){}//跟类初始化列表一样 }; template<class T> class BSTree { private: Node<T> *root;//这里写Node *root是错的,需要给结构体模板传参Node<T> *root void destroy(); public: BSTree():root(NULL){} //构造函数,初始化 BSTree(BSTree &c)//重载复制构造函数,防止浅拷贝 { if(c.getRoot()!=NULL) { queue< Node<T>* > n1; queue< Node<T>* > n2; root=new Node<T>(c.getRoot()->cdata); Node<T> *storage=root; n1.push(c.getRoot()); n2.push(root); while(!n1.empty())//层次 { Node<T> *te=n1.front(); Node<T> *te2=n2.front(); n1.pop(); n2.pop(); if(te->lchild!=NULL) { te2->lchild=new Node<T>(te->lchild->cdata); n1.push(te->lchild); n2.push(te2->lchild); } if(te->rchild!=NULL) { te2->rchild=new Node<T>(te->rchild->cdata); n1.push(te->rchild); n2.push(te2->rchild); } } root=storage; } } ~BSTree()//析构函数,回收内存 { destroy(); } Node<T>* getRoot() { return root; } bool insertNode(Node<T>* t);//增 Node<T> *findX(T x)const;//查 void removeX(T x);//删 void midtraversal(Node<T> *te)const; bool isTreeEmpty()const; }; template<class T> inline bool BSTree<T>::insertNode(Node<T> *t) { if(root==NULL) { root=t; return true; } Node<T> *te=root; while(true) { if(t->cdata<root->cdata) { if(root->lchild!=NULL) { root=root->lchild; } else { root->lchild=t; root=te; return true; } } else if(t->cdata>root->cdata) { if(root->rchild!=NULL) { root=root->rchild; } else { root->rchild=t; root=te; return true; } } else { root=te; return false; } } } template<class T> inline void BSTree<T>::destroy() { cout<<"delete: "; if(root==NULL) { return; } stack< Node<T>* > s; s.push(root); while(!s.empty())//先序 { if(s.top()->lchild==NULL&&s.top()->rchild==NULL) { Node<T> *te=s.top(); s.pop(); cout<<te->cdata<<"\t"; delete te; } else { while(s.top()->lchild!=NULL) { Node<T> *te=s.top()->lchild; s.top()->lchild=NULL; s.push(te); } while(s.top()->rchild!=NULL) { Node<T> *te=s.top()->rchild; s.top()->rchild=NULL; s.push(te); } } } } template<class T> inline bool BSTree<T>::isTreeEmpty()const//BSTree::isTreeEmpty()是错的,类模板需要传参BSTree<T>::isTreeEmpty() { if(root==NULL) { return true; } return false; } template<class T> inline void BSTree<T>::midtraversal(Node<T> * te)const//中序 { if(te==NULL) { return; } BSTree<T>::midtraversal(te->lchild); cout<<te->cdata<<"(ad: "<<te<<")"<<"\t"; BSTree<T>::midtraversal(te->rchild); } template<class T> inline Node<T>* BSTree<T>::findX(T x)const { Node<T>* storage=root; while(storage!=NULL) { if(x<storage->cdata) { storage=storage->lchild; } else if(x>storage->cdata) { storage=storage->rchild; } else { return storage; } } return storage; } template<class T> inline void BSTree<T>::removeX(T x) { Node<T> *te=findX(x); if(te==NULL)//情况一:不存在x,直接返回 { return; } if(te->lchild==NULL&&te->rchild==NULL)//情况二:叶子节点,直接删 { delete te;//调用指针的析构函数,来释放对象内存 return; } if(te->lchild==NULL&&te->rchild!=NULL)//情况三:单子树,直接删,让子树代替原节点 { te->cdata=te->rchild->cdata; te->lchild=te->rchild->lchild; te->rchild=te->rchild->rchild; delete te->rchild; return; } if(te->lchild!=NULL&&te->rchild==NULL) { te->cdata=te->lchild->cdata; te->lchild=te->lchild->lchild; te->rchild=te->lchild->rchild; delete te->lchild; return; } if(te->lchild!=NULL&&te->rchild!=NULL)//情况四:双子树,让直接后继代替原节点,直接后继是叶子节点直接删,有单子树,按上操作 { //找直接后继,如找9的直接后继,就是找9的右子树中比9大的最小数 Node<T> *te2=te->rchild; while(te2->lchild!=NULL) { te2=te2->lchild; } //直接后继代替原节点 te->cdata=te2->cdata; //删除直接后继 if(te2->rchild==NULL) { delete te2; return; } if(te2->rchild!=NULL) { te2->cdata=te2->rchild->cdata; te2->lchild=te2->rchild->lchild; te2->rchild=te2->rchild->rchild; delete te2->rchild; return; } } } int main() { { int c[]={3,9,-1,4,2,7,9,19,10,12}; BSTree<int> a; for(int i=0;i<10;i++) { a.insertNode(new Node<int>(c[i])); } a.midtraversal(a.getRoot()); cout<<endl; a.removeX(9); a.midtraversal(a.getRoot()); cout<<endl; if(a.findX(9)!=NULL) { cout<<a.findX(9)->cdata<<endl; } else { cout<<"can't find"<<endl; } BSTree<int> b(a); b.midtraversal(b.getRoot()); cout<<endl; } return 0; }
思考:在构建二叉查找树之前,对输入数据进行洗牌,会不会更好。但是如果数据不是像例子中一次性给出,那么也就没办法对输入数据进行洗牌了。
b.红黑树
是一种二叉查找树,也是一种平衡树。典型的用途是实现关联数组(c++中的map,set ?)
节点数据结构如下:
template<class Type> struct Node { Type val;//节点存储数据 bool color;//true为红,false为黑 Node* lchild; Node* rchild; Node* parent; Node(Type temp):val(temp),color(true),lchild(NULL),rchild(NULL),parent(NULL){} };成为一颗红黑树的条件:
1.节点非黑即红(对于分析没有实际意义)
2.根节点是黑色的(说不出来,但写插入时,很有用,情况四再次向上调整时有用,父亲节点是红色时,一定存在祖父节点的判定...模糊)
3.叶节点(空节点)是黑色的(为方便代码编写和算法实现)
4.红节点的子节点是黑色的(并不意味着每条路径上的节点都是黑红交替的)
5.对于每个节点,从该节点到其子孙叶节点(空节点)的所有路径上包含的黑节点数目是相同的
红黑树的平衡性讨论:
由条件5可知:因为从一点出发,任何一条路径到叶节点所经历的黑节点个数是相同的,所以一条路径上的红节点个数越多,路径也就越长
由条件4和上条推论可知:因为红节点的子节点一定是黑的,意味着两个红节点是不可能连续,所以红节点最多时,就是在每两个黑节点之间插上1个,所以红节点最多与黑节点个数相同
由上可推出:
最长路径是红黑交替出现长度为2n(n为黑节点个数)
最短路径是纯黑节点长度为n
最长路径最多是最短路径的两倍,这保证了这棵树的平衡性。(当然对比严格的平衡二叉树来说,平衡性肯定是要差些的)
红黑树的插入:(中心思想:插入新节点,不能破坏性质1~5,这样才能保证树的平衡)
写的很好:http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html
情况1:根节点为空,插入节点设为根节点,color设为黑
情况2:已经存在该节点,直接返回
情况3:父亲节点为黑,插入后,无需调整,直接返回
情况4:父亲节点为红,且叔叔节点也为红,插入后,将父亲节点设为黑,叔叔节点设为黑,祖父节点(父亲节点为红,则至少有祖父root为黑)设为红,将祖父节点作为新节点,再次向上调整
情况5:父亲节点为红,叔叔节点为黑,父亲节点为左(右)孩子,新节点也为左(右)孩子,右(左)单旋,原父亲节点站在了原祖父节点的位置上,原父亲节点转黑,原祖父节点转红
情况6:父亲节点为红,叔叔节点为黑,父亲节点为左(右)孩子,新节点为右(左)孩子,左(右)旋,各节点颜色不变。现在成了情况5,转情况5处理
红黑树的删除:(中心思想:删除某个节点,要保证黑节点个数不变,这样性质5才不会被破坏)
写的很好:http://blog.csdn.net/spch2008/article/details/9338923
最重要的一点,以下结构会破坏性质5,所以不会出现(盗图):
详细参看上述博客
红黑树代码:(仅插入部分,删除真的好麻烦!)
#include<iostream> #include<queue> using namespace std; template<class Type> struct Node { Type val;//节点存储数据 bool color;//true为红,false为黑 Node* lchild; Node* rchild; Node* parent; Node(Type x):val(x),color(true),lchild(NULL),rchild(NULL),parent(NULL){} }; template<class T> class RBTree//析构函数和复制构造函数不再重载,大致与二叉查找树相同 { private: Node<T>* root; Node<T>* findInsertPos(T x);//寻找插入点 bool judgeLR(T x,Node<T> *y);//判断是左孩子(true)还是右孩子(false) void adjust(Node<T> *x);//插入节点之后需要调整 public: Node<T>* getRoot() { return root; } void insertNode(T x); void midtraversal(Node<T> *te)const; void leveltraversal()const; }; template<class T> inline void RBTree<T>::leveltraversal()const { cout<<"层次:"<<endl; Node<T> *storage=root; queue< Node<T>* > q; q.push(storage); while(!q.empty()) { Node<T> * te=q.front(); q.pop(); cout<<te->val<<"("<<te->color<<")\t"; if(te->lchild!=NULL) { q.push(te->lchild); } if(te->rchild!=NULL) { q.push(te->rchild); } } cout<<endl; } template<class T> inline void RBTree<T>::midtraversal(Node<T> *te)const { if(te==NULL) { return; } RBTree<T>::midtraversal(te->lchild); cout<<te->val<<"("<<te->color<<")"<<"\t"; RBTree<T>::midtraversal(te->rchild); } template<class T> inline bool RBTree<T>::judgeLR(T x,Node<T> *y) { if(x<y->val) { return true; } else { return false; } } template<class T> inline Node<T>* RBTree<T>::findInsertPos(T x) { Node<T> *storage=root; while(storage!=NULL) { if(x<storage->val) { if(storage->lchild!=NULL) { storage=storage->lchild; } else { return storage; } } else if(x>storage->val) { if(storage->rchild!=NULL) { storage=storage->rchild; } else { return storage; } } else { return NULL; } } return storage; } template<class T> inline void RBTree<T>::adjust(Node<T> *x) { if(x==root)//< 距离root0,就会直接返回了 > { x->color=false; return; } if(!x->parent->color)//情况三:父亲节点是黑色的,无需操作,直接返回< 距离root1,因为root是黑的,所以到此步也就返回了 > { return; } //< 距离root2以上距离的,才会做以下操作,所以x->father->father不会非法 > Node<T> *f=x->parent; Node<T> *u; bool fcolor=f->color; bool ucolor; bool fgchild=judgeLR(f->val,f->parent); bool mfchild=judgeLR(x->val,f); if(fgchild) { u=f->parent->rchild; } else { u=f->parent->lchild; } if(u==NULL) { ucolor=false; } else { ucolor=u->color; } if(fcolor&ucolor)//情况四:父亲节点与叔叔节点都是红的,父亲节点和叔叔节点全改为黑,祖父节点改为红,把祖父节点当做新插入节点,继续调整 { f->color=false; u->color=false; f->parent->color=true; adjust(f->parent); return; } bool tag; bool gffchild=false; Node<T> *g=f->parent; Node<T> *gf=g->parent; if(gf==NULL)//g是root { tag=true; } else { tag=false; gffchild=judgeLR(g->val,gf); } if(fgchild&mfchild)//情况五:父亲节点为红,叔叔节点为黑,父亲节点为左,我也为左,即同侧,左单旋 { g->parent=f; g->lchild=f->rchild; g->color=true; f->rchild=g; f->color=false; if(tag) { f->parent=NULL; root=f; return; } else { if(gffchild) { gf->lchild=f; } else { gf->rchild=f; } f->parent=gf; return; } } if((!fgchild)&(!mfchild))//情况五:父亲节点为红,叔叔节点为黑,父亲节点为右,我也为右,即同侧,右单旋 { g->parent=f; g->rchild=f->lchild; g->color=true; f->lchild=g; f->color=false; if(tag) { f->parent=NULL; root=f; return; } else { if(gffchild) { gf->lchild=f; } else { gf->rchild=f; } f->parent=gf; return; } } if(fgchild&(!mfchild))//情况六:父亲节点为红,叔叔节点为黑,父亲节点为左,我为右,单旋一次就成了情况五 { f->rchild=x->lchild; f->parent=x; g->lchild=x; x->parent=g; x->lchild=f; adjust(f); return; } if((!fgchild)&mfchild)//情况六:父亲节点为红,叔叔节点为黑,父亲节点为右,我为左,单旋一次就成了情况五 { f->lchild=x->rchild; f->parent=x; g->rchild=x; x->parent=g; x->rchild=f; adjust(f); return; } } template<class T> inline void RBTree<T>::insertNode(T x) { if(root==NULL)//情况一:树空,根节点为黑 { root=new Node<T>(x); root->color=false; return; } if(findInsertPos(x)==NULL)//情况二:已经存在,无需插入,直接返回 { return; } /*****下列情况,考查的只有,本身、爹、叔叔的颜色、左右身份*****/ /*****下列情况,先插入,再调整*****/ Node<T> *f=findInsertPos(x); bool mfchild=judgeLR(x,f); if(mfchild) { f->lchild=new Node<T>(x); f->lchild->parent=f; adjust(f->lchild); } else { f->rchild=new Node<T>(x); f->rchild->parent=f; adjust(f->rchild); } } int main() { int c[]={3,9,-1,4,2,7,91,19,10,12,9}; RBTree<int> a; for(int i=0;i<11;i++) { a.insertNode(c[i]); } cout<<"中序:"<<endl; a.midtraversal(a.getRoot()); cout<<endl; a.leveltraversal(); return 0; }
红黑树与严格的AVL树(高度平衡二叉树)(考研时数构考过)的比对:
转自:http://blog.csdn.net/klarclm/article/details/7780319
相对于AVL树而言,红黑树牺牲了严格的高度平衡的优越条件为 代价,红黑树能够以O(log n)的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决(参看插入操作)。当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。
当然,红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。
c.哈夫曼树(编码)
#include<iostream> #include<cstdlib> #include<queue> using namespace std; struct Tree { Tree* lchlid; Tree* rchlid; int f;//频率 int data;//值 }; struct cmp//与sort的cmp不同,结构体中重载调用操作符。也可以重载>操作符,priority_queue<Node,vector<Node>,greater<Node>> Q; { bool operator()(Tree a,Tree b) { return a.f>b.f;//>升序,<降序 } }; int random(int start,int end) { return start+rand()%(end-start); } void HuffmanTree(priority_queue<Tree,vector<Tree>,cmp> &q) { while(q.size()>=2) {/* Tree a=q.top(); cout<<"&a="<<&a<<endl;//局部变量的地址每次申请的都是相同的,所以后续错了 q.pop(); Tree b=q.top(); cout<<"&b="<<&b<<endl;/花了2个多小时查的,此处需注意了 q.pop(); Tree c; c.lchlid=&a; c.rchlid=&b; c.f=a.f+b.f; c.data=-1; q.push(c);*/ Tree *a=new Tree; a->data=q.top().data; a->lchlid=q.top().lchlid; a->rchlid=q.top().rchlid; a->f=q.top().f; q.pop(); Tree *b=new Tree; b->data=q.top().data; b->lchlid=q.top().lchlid; b->rchlid=q.top().rchlid; b->f=q.top().f; q.pop(); Tree c; c.lchlid=a; c.rchlid=b; c.f=a->f+b->f; c.data=-1; q.push(c); } } void LT(const priority_queue<Tree,vector<Tree>,cmp> &p) { queue<Tree*> q; Tree n=p.top(); q.push(&n); while(!q.empty()) { Tree *temp=q.front(); q.pop(); if(temp->data==-1) { cout<<"Node\t"; } else { cout<<temp->f<<"\t"; } if(temp->lchlid!=NULL) { q.push(temp->lchlid); } if(temp->rchlid!=NULL) { q.push(temp->rchlid); } } } int main() { int num; priority_queue<Tree,vector<Tree>,cmp> q; cin>>num; for(int i=0;i<num;i++) { Tree temp; temp.lchlid=NULL; temp.rchlid=NULL; temp.f=random(0,1000); temp.data=random(1,50); q.push(temp); cout<<temp.f<<"\t"; } cout<<endl; HuffmanTree(q); LT(q); }
d.并查集
初始化,查根,合并代码如下
#include<iostream> #define Maxv 200 using namespace std; int data[Maxv]; //data[i]=j,元素i的祖宗是j void initial(int data[])//初始化 { for(int i=0;i<Maxv;i++) { data[i]=i;//初始化自己是自己的祖宗 } } int findFather(int data[],int x)//查祖宗 { if(data[x]==x) { return x;//自己是自己的祖宗,返回 } return findFather(data,data[x]);//把自己的爹,做参数,继续寻找 } void Union(int data[],int x,int y)//合并两个集合 { int xggfather=findFather(data,x);//找到x的祖宗 int yggfather=findFather(data,y);//找到y的祖宗 data[xggfather]= yggfather;//把y的祖宗作为x祖宗的祖宗 }并查集应用实例:畅通工程,Kruscal最小生成树
Kruscal最小生成树:
#include<iostream> #include<queue> using namespace std; #define Maxv 100+5 struct Node { int v2; int v1; int len; }; struct cmp { bool operator()(Node a,Node b) { return a.len>b.len; } }; int dis[Maxv][Maxv];//dis[i][j]等于0时表示不连通 ,不等于1时表示边权值 int fa[Maxv];//father,并查集 int Getfa(int i)//查找根节点的函数 { if(fa[i]!=i)//如果不是根节点 fa[i]=Getfa(fa[i]);//找根节点 return fa[i];//返回节点i所在集合的根节点 } int main() { int sum;//最小生成树代价 priority_queue<Node,vector<Node>,cmp> Q;//声明小顶堆,返回最小数 int vn;//图中的顶点个数 int i; int j; cin>>vn; //输入图 for(i=1;i<=vn;i++) { for(j=1;j<=vn;j++) { cin>>dis[i][j]; } } for(i=1;i<=vn;i++) { fa[i]=i;//并查集,father,一开始有vn个节点,就有vn个集合 } while(!Q.empty()) { Q.pop(); } //把每条边压入堆中 for(i=1;i<vn;i++) { for(j=i+1;j<=vn;j++) { if(dis[i][j])//如果边权值不为0,即顶点之间有边,压入该边 { Node e; e.v1=i; e.v2=j; e.len=dis[i][j]; Q.push(e); } } } sum=0; while(Q.size()!=0) { Node e; e=Q.top(); Q.pop(); if(Getfa(e.v1)!=Getfa(e.v2))//若两个顶点不属于同一个点集,表示该边不是回路;也即两个节点的根节点是否相同 { //根节点不同,则为不同集合,不构成回路 sum=sum+e.len; fa[Getfa(e.v2)]=Getfa(e.v1);//把e.v1的根节点作为e.v2的根节点的爹,也即合并两个集合 } } cout<<sum; return 0; }
相关文章推荐
- Des 加密处理 iOS 和 安卓 与服务器 处理时 遇到的 补位问题
- windows系统清理与维护
- linux笔记:压缩解压命令gzip,gunzip,tar,zip,unzip,bzip2,bunzip2
- ZUFE OJ 2301 GW I (3)
- App 引导界面
- Hibernate一级缓存【Hibernate】
- 十月,再见;你好,十一月
- Springmvc异常处理【Springmvc】
- 数组求和与课后作业
- 6种绝招让你花1分钟增寿20岁
- 用HTML/JS/PHP方式实现页面延时跳转
- usb转rs232驱动无效,已经电脑自动扫描检测硬件改动.设备无法运行错误代码10
- 黑马程序员——面向对象(二)
- 关于鸿学金信原始股的一个坏消息与好消息
- Springmvc-freemarker 【Springmvc】
- ubuntu15.04 mysql5.6.27编码格式配置
- 程序下载和安装
- matlab与c/c++混合编程
- nginx平台初探(五)
- 线程的创建