一.一般树结点和树的ADT
template <typename E>
class GTNode{
private:
E value;
GTNode* parent;
GTNode* leftmostChild;
GTNode* rightSibling;
public:
GTNode() { parent = leftmostChild = rightSibling = NULL; }
GTNode(E v, GTNode<E>* lc = NULL, GTNode<E>* rs = NULL) {
value = v; leftmostChild = lc; rightSibling = rs;
}
E value() { return value; }
GTNode* parent() { return parent; }
GTNode* leftmostChild() { return leftmostChild; }
GTNode* rightSibling() { return rightSibling; }
bool isLeaf() { return leftmostChild == NULL; }
void setValue(E& v) { value = v; }
void insertFirst(GTNode<E>*);
void insertNext(GTNode<E>*);
void removeFirst();
void removeNext();
};
template <typename E>
class GenTree {
private:
GTNode<E>* root;
public:
void clear();
GTNode<E>* getroot() { return root; }
void newroot(E&, GTNode<E>*, GTNode<E>*);
void print() { printhelp(root); }
};
二.一般树的遍历
和二叉树类似,但是除了中序遍历对一般树没有太大的意义
树的遍历用的还是递归方法,和二叉树类似
如:利用树的遍历进行打印
template <typename E>
void printhelp(GTNode<E>* rt) {
if (rt->leftmostChild == NULL) cout << "Leaf node : ";
else cout << "Inner node : ";
cout << rt->value();
for (GTNode<E>* start = rt->leftmostChild(); start != NULL; start = start->rightSibling())
printhelp(start);
}
又:利用树的遍历,数出树所有的结点
template <typename E>
void getCount(GTNode<E>* rt) {
if (rt == NULL) return 0;
int count = 1;
for (GTNode<E>* temp = rt->leftmostChild(); temp != NULL; temp = temp->rightSibling())
{
count += getCount(temp);
}
return count;
}
三. 父指针表示法
(1)父指针表示法:对每个结点只保存一个指针域指向父结点,特别适合解决判断两个结点是否在同一个树中的问题。
(2)父指针表示法常用的两种操作:FIND和UNION
FIND:对给定的一个结点,找到它的根节点
UNION:合并两个集合
代码实现:
template <typename E>
class GenTree {
private:
int* array;
int size;
int FIND(int) const;
const int ROOT = -1;
public:
GenTree(int sz) {
size = sz;
array = new int[size];
for (int i = 0; i < size; i++)
array[i] = ROOT;
}
~GenTree() {
delete[] array;
}
bool differ(int a, int b) {
return FIND(a) != FIND(b);
}
int FIND(int curr)const {
while (array[curr] != ROOT) curr = array[curr];
return curr;
}
void UNION(int a, int b) {
int root1 = array[a];
int root2 = array[b];
if (root1 != root2)
root2 = root1;
}
};
(3)解决一个问题:如何降低合并操作时树的高度?
方法一:重量权衡合并规则:把结点少的树和结点多的树合并时,把结点少的树的父指针指向结点多的树
方法二:路径压缩:在FIND操作时,把当前结点所有的祖先结点的父结点都设置为根结点,这样做能够使得树的高度最低,使得FIND操作的复杂度非常接近常数
四. 实现树的方法:
(1)子结点表表示法:
(2)左子结点/右兄弟结点表示法:
(3)动态结点表示法:
(4)动态左子结点/右兄弟结点表示法:
五. 顺序表示法:
存储一系列结点的值,其中包含了尽可能少但是对于重建树必不可少的信息