C++ | Tree的实现(适用于一般的树)

本文介绍了一种采用孩子-兄弟表示法的普通树存储结构,并详细讲解了如何使用C++实现该结构,包括创建树、求树的深度及打印树的所有路径等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 其实主要是采用类似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;	
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值