线索二叉树
二叉树的遍历运算是将二叉树中结点按一定规律线性化的过程。
当以二叉链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在遍历序列中的前驱和后继信息。
要得到这些信息可采用以下两种方法:
1.将二叉树遍历一遍,在遍历过程中便可得到结点的前驱和后继,但这种动态访问浪费时间。
2.充分利用二叉链表中的空链域, 将遍历过程中结点的前驱、 后继信息保存下来。
线索链表:
线索:将二叉链表中的空指针域指向前驱结点和后继结点的指针被称为线索。
线索化:使二叉链表中结点的空链域存放其前驱或后继信息的过程称为线索化。
线索二叉树:加上线索的二叉树称为线索二叉树。
线索二叉树的存储结构:线索链表
ltag:
0: lchild指向该结点的左孩子
1: lchild指向该结点的前驱结点
rtag:
0: rchild指向该结点的右孩子
1: rchild指向该结点的后继结点
中序线索链表类的声明:
enum flag {Child, Thread};
template <class T>
struct ThrNode
{
T data;
ThrNode<T> *lchild, *rchild;
flag ltag, rtag;
};
template <class T>
class InThrBiTree{
ThrNode<T> *root;
ThrNode<T> *Creat();
void ThrBiTree(ThrNode<T> *root);
public:
InThrBiTree();
~InThrBiTree();
ThrNode *Next(ThrNode<T> *p);
void InOrder(ThrNode<T> *root);
};
template<class T>
ThrNode<T>* InThrBiTree<T>::Creat(){
ThrNode<T> *root;
T ch;
cout<<"请输入创建一棵二叉树的结点数据"<<endl;
cin>>ch;
if (ch=="#") root = NULL;
else{
root=new ThrNode<T>;
root->data = ch;
root->ltag = Child; root->rtag = Child;
root->lchild = Creat();
root->rchild = Creat();
}
return root;
}
template <class T>
void ThrBiTree<T>::ThrBiTree (ThrNode<T>*root) {
if (root==NULL) return;//递归结束条件
ThrBiTree(root->lchild);
if (!root->lchild){//对root的左指针进行处理
root->ltag = Thread;
root->lchild = pre; //设置pre的前驱线索
}
if (!root->rchild) root->rtag = Thread;
if(pre != NULL){
if (pre->rtag==Thread) pre->rchild = root;
}
pre = root;
ThrBiTree(root->rchild);
}
ThrNode<T>* pre = NULL
template <class T>
InThrBiTree<T>::InThrBiTree( )
{
//ThrNode<T>* pre = NULL;
this->root = Creat( );
ThrBiTree(root);
}
template <class T>
ThrNode<T>* InThrBiTree<T>::Next(ThrNode<T>* p)
{
ThrNode<T>* q; //要查找的p的后继
if (p->rtag==Thread)
q = p->rchild;
else{
q = p->rchild;
while (q->ltag==Child) {
q = q->lchild;
}
}
return q;
}
template <class T>
void InThrBiTree<T>::InOrder(ThrNode<T> *root){
ThrNode<T>* p = root;
if (root==NULL) return;
while (p->ltag==Child){
p = p->lchild;
}
cout<<p->data<<" ";
while (p->rchild!=NULL) {
p = Next(p);
cout<<p->data<<" ";
}
cout<<endl;
}
中序线索化二叉树:递归实现
基本思想:
在遍历的过程中完成线索化
可以采用前序、中序、后序遍历建立前序线索二叉树、中序线索二叉树和后序线索二叉树。
中序线索二叉树的构造方法:
中序线索化根结点的左子树;
对根结点进行线索化;
中序线索化根结点的右子树。
算法分析:
函数设置形参root和全局变量pre,分别表示要处理的树的根结点和其前驱结点
如果root!=NULL
中序线索化root的左子树
中序线索化root本身
如果root->lchild= =NULL
root->left=pre,root->ltag=1;
如果root->rchild==NULL,root->rtag=1,
如果pre!=NULL, 并且pre->rtag=1,
pre->rchild=root,;
pre=root
中序线索化root的右子树
并查集
一、并查集的存储结构
不相交集合是对集合的一种划分,将集合S划分为若干子集,这些子集之间没有交集,且所有子集并即为集合S。不相交集合的两个基本操作是查找和合并,查找是找出某个元素属于哪个子集,合并是把两个子集合并成一个自己,不相交集合也称并查集。
struct ElemType
{
char data;//假定并查集的元素为字符型
}
二、并查集的实现
const int MaxSize = 100; //假设集合最多100个元素
class UnionFind
{
public:
UnionFind(char ch[ ], int n); //构造函数,每个元素构成一个子集
~UnionFind(); //析构函数
int Find(char x); //查找元素x所在子树的根结点
void Union(char x, char y); //合并元素x和y所在子集
private:
ElemType elem[MaxSize]; //双亲表示法存储
int length; //集合的元素个数
};
UnionFind :: UnionFind(char ch[ ], int n)
{
length = n;
for (int i = 0; i < length; i++)
{
elem[i].parent = -1;
elem[i].data = ch[i];
}
}
UnionFind :: ~UnionFind(){}//采用静态存储分配,在并查集变量退出作用域是自动释放,为空
int UnionFind :: Find(char x)
{
int i;
for (i = 0; i < length; i++)
if (elem[i].data == x) break;
while (elem[i].parent != -1)
i = elem[i].parent;
return i;
}
void UnionFind :: Union(char x, char y)
{
int vex1 = Find(x);
int vex2 = Find(y);
if (vex1 != vex2)
elem[vex2].parent = vex1;
}
int main()
{
char str[6] = {'a', 'b', 'c', 'd', 'e', 'f'};
int flag[6];
UnionFind UF{str, 6};
UF.Union('a', 'b');
UF.Union('a', 'c');
UF.Union('d', 'e');
for (int i = 0; i < 6; i++)
{
flag[i] = UF.Find(str[i]);
cout << flag[i] << ":" << str[i] << endl;
}
return 0;
}