- 其实主要是采用类似c这种面向过程的语言的接口实现办法,用c++更多只是为了调用队列,栈等一些接口
- 网上资料大部分树的实现都是二叉树,而实际常见的树一般是普通的树
- 所以我们要学会通过二叉树的思想来转换到普通的树来使用
- 本文采用的存储结构为(孩子-兄弟)结点表示法,也叫二叉链表,有不懂得地方可以查看我的另外一篇关于树的存储结构的文章
- 本文重点讨论三个函数,其他实现函数都大同小异
- 求树的深度
- 打印树的路径
- 如何创建一颗普通的树
树的存储结构:
typedef char ElemType;
typedef struct CSNode {
ElemType data;
struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;
求树的深度:
unsigned int TreeDepth(CSTree T) {
if (T) {
return (1+TreeDepth(T->firstchild))>TreeDepth(T->nextsibling)?(1+TreeDepth(T->firstchild)):TreeDepth(T->nextsibling);
}
return 0;
}
方法基本类似二叉树,只是一点打印兄弟结点的时候因为兄弟结点的根节点是他的兄弟,所以深度应该去掉那个根节点
树的路径打印
void AllPath(CSTree T, stack<ElemType> *S1) {
//stack<ElemType> S1;
while (T != NULL) {
S1->push(T->data);
if (T->firstchild == NULL) {
stack<ElemType> S2;
S2 = (*S1);
while(!S2.empty()) {
printf("%c\n",S2.top());
S2.pop();
}
}
else {
AllPath(T->firstchild, S1);
}
S1->pop();
T=T->nextsibling;
}
}
这里要说一下,虽然思路不难想,自己画一下图便很容易想通,但是我debug de了很久,而且一度坚持认为自己没错,归根到底还是递归用得不熟练,一开始把栈作为形参只是在函数内创建,所以每一遍递归栈都会刷新一遍而不会保留下来,所以要创建一个指向栈的指针,使得每次递归栈的信息保存下来
创建树
- 虽然这个内容是前面连个的基础,但第一步往往是最难的,这个也不例外
- 采取的思路是根节点孩子节点对来创建
- 运行时直接输入
#AABACADCECFFG##
即可,注意每一对之间不要加空格,因为空格会被识别为其他的字符 - 因为这种存储结构较为复杂,故采用递归思路可能会导致创建混乱,利用队列来创建
void CreateTree(CSTree *T) {
(*T) = NULL;
ElemType Felem;
ElemType Selem;
CSNode *r = NULL; //r为指向当前结点的指针
CSNode *p = NULL; //p为指向队列front的指针
queue<CSNode*> Q;
for (scanf("%c%c",&Felem,&Selem); Selem != '#'; scanf("%c%c",&Felem,&Selem)) {
CSNode *node;
node = (CSNode*)malloc(sizeof(CSNode));
node -> data= Selem;
node -> firstchild = NULL;
node -> nextsibling = NULL;
Q.push(node);
if (Felem == '#') {
(*T) = node;
r = node;
}
else {
while(Q.front()->data != Felem) {
Q.pop();
}
p = Q.front();
if (!(p->firstchild)) {
p->firstchild = node;
r = node;
}
else {
r->nextsibling = node;
r = node;
}
}
}
}
所有代码参考如下:
Tree.hpp
// - - - - - 采用二叉链表的表示方法 - - - - -
#ifndef _TREE_H_
#define _TREE_H_
//#include <stdbool.h>
#include <iostream>
#include <stack>
using namespace std;
typedef char ElemType;
typedef struct CSNode {
ElemType data;
struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;
void CreateTree(CSTree *T);
void DestroyTree(CSTree *T);
unsigned int TreeDepth(CSTree T);
void AllPath(CSTree T, stack<ElemType> *S1);
void PrintTree(CSTree T);
#endif
Tree.cpp
#include <iostream>
#include "Tree.hpp"
#include <stdio.h>
#include <stack>
#include <queue>
#include <stdlib.h>
using namespace std;
void CreateTree(CSTree *T) {
(*T) = NULL;
ElemType Felem;
ElemType Selem;
CSNode *r = NULL;
CSNode *p = NULL;
queue<CSNode*> Q;
for (scanf("%c%c",&Felem,&Selem); Selem != '#'; scanf("%c%c",&Felem,&Selem)) {
CSNode *node;
node = (CSNode*)malloc(sizeof(CSNode));
node -> data= Selem;
node -> firstchild = NULL;
node -> nextsibling = NULL;
Q.push(node);
if (Felem == '#') {
(*T) = node;
r = node;
}
else {
while(Q.front()->data != Felem) {
Q.pop();
}
p = Q.front();
if (!(p->firstchild)) {
p->firstchild = node;
r = node;
}
else {
r->nextsibling = node;
r = node;
}
}
}
}
void DestroyTree(CSTree *T) {
if (*T) {
DestroyTree(&((*T)->firstchild));
DestroyTree(&((*T)->nextsibling));
free(*T);
(*T) = NULL;
}
}
unsigned int TreeDepth(CSTree T) {
if (T) {
return (1+TreeDepth(T->firstchild))>TreeDepth(T->nextsibling)?(1+TreeDepth(T->firstchild)):TreeDepth(T->nextsibling);
}
return 0;
}
void AllPath(CSTree T, stack<ElemType> *S1) {
//stack<ElemType> S1;
while (T != NULL) {
S1->push(T->data);
if (T->firstchild == NULL) {
stack<ElemType> S2;
S2 = (*S1);
while(!S2.empty()) {
printf("%c\n",S2.top());
S2.pop();
}
}
else {
AllPath(T->firstchild, S1);
}
S1->pop();
T=T->nextsibling;
}
}
void PrintTree(CSTree T) {
if (T) {
cout << T->data << endl;
PrintTree(T->firstchild);
PrintTree(T->nextsibling);
}
}
main.cpp
#include <iostream>
#include "Tree.hpp"
using namespace std;
int main () {
CSTree T;
CreateTree(&T);
//cout << T->nextsibling->data << endl;
//PrintTree(T);
stack<ElemType> s;
AllPath(T, &s);
/*while (!s.empty()) {
cout << s.top() << endl;
s.pop();
}*/
cout << TreeDepth(T) << endl;
DestroyTree(&T);
if (!T) {
cout << "delete successfully" << endl;
}
return 0;
}