树(一):基本知识

概念:

n(n>=0) 个节点构成的有限集合

  • 空树
    • n = 0
  • 非空树
    • 有一个根节点
    • 其余节点分为m(m>0)个互不相交的有限集,每个集合本身也是树

非树:
在这里插入图片描述
树:

特点:

  1. 子树不相交
  2. 除了根节点外,每个节点有且仅有一个父节点
  3. n个节点的树有n-1条边

基本术语:

  1. 节点的度(Degree):一个节点的子节点的个数
  2. 树的度:树中,最大的节点的度
  3. 叶节点(Leaf):度为0的节点
  4. 父节点(Parent):有子树的节点,且是子树的的根节点
  5. 子节点(Child):A是B的父节点,则B是A的子节点
  6. 兄弟节点(Sibling):具有同一父节点的各节点彼此是兄弟节点
  7. 路径:从节点n到nk的路径为一个节点序列
  8. 路径长度:路径中所包含边的个数为路径长度
  9. 祖先节点(Ancestor):沿树根到某个节点上的所有节点都是这个节点的祖先节点
  10. 子孙节点(Descendant):某一节点的子树中所有节点是这个节点的子孙
  11. 节点的层次(Level):规定根节点在1层,其他任意节点是其分节点的层数+1
  12. 树的深度(Depth):树中所有节点中的最大层次是这颗树的深度

存储方式:

在这里插入图片描述

  1. 数组
    通常的树很难用数组表示(二叉树除外)
  2. 链表
    这种方式构建链表,发现链表中的指针数量是根据整个树的度来决定的,当前树的度是3,也就是每个节点都有3个指针,如果一个节点中没有子节点,那么他会浪费会浪费很多空间
    在这里插入图片描述
    优化:儿子-兄弟表示法(类似于二叉树)
    在这里插入图片描述
    也就是左边放置子节点,右边放置兄弟节点
    在这里插入图片描述

简单的实现:

根据给的节点
{
(‘A’, ‘B’),(‘A’, ‘C’),(‘A’, ‘D’)
(‘B’, ‘E’),(‘B’, ‘F’)
(‘C’, ‘G’)
(‘D’, ‘H’),(‘D’, ‘I’),(‘D’, ‘J’)
(‘E’, ‘K’),(‘E’, ‘L’)
(‘H’, ‘M’)
}
注:下面实现不包括值相同的节点,即B->B,这种操作不行,需要添加标志,注明节点的顺序

#include <iostream>
#include <string>
#include <vector>
#include <map>

using namespace std;

// 节点结构
struct TreeNode
{
	char value;
	TreeNode* child;
	TreeNode* nextBrother;
	TreeNode(char val):value(val), child(NULL), nextBrother(NULL)
	{}
};

// 树
class Tree
{
public:
	TreeNode* root;
	Tree() {}
	~Tree();
	void CreateTree(std::map<int, std::map<char, char>> data); // 创建树
	void DestroyNode(TreeNode* node);						   // 销毁树
	TreeNode* GetNodeByVal(TreeNode* node, char val);          // 根据值获取节点
};

void Tree::CreateTree(map<int, map<char, char>> data)
{
	TreeNode* node = NULL;
	for (int i = 0;i < data.size();i++)
	{
		map<char, char>::iterator iter = data[i].begin();
		node = GetNodeByVal(node, iter->first);
		if ( node == NULL)
		{
			node = new TreeNode(iter->first);
			if (i == 0)
			{
				root = node;
			}
		}
		if (node->child == NULL)
		{
			node->child = new TreeNode(iter->second);
		}
		else
		{
			TreeNode** next = &(node->child->nextBrother);
			while (*next != NULL)
			{
				next = &((*next)->nextBrother);
			}
			*next = new TreeNode(iter->second);
		}
	}
}

TreeNode* Tree::GetNodeByVal(TreeNode* node, char val)
{
	if (node == NULL || (node!=NULL && node->value == val))
	{
		return node;
	}

	TreeNode* cNode = GetNodeByVal(node->child, val);
	if (cNode != NULL)
	{
		return cNode;
	}
	else
	{
		TreeNode* bNode = GetNodeByVal(node->nextBrother, val);
		return bNode;
	}
}

Tree::~Tree()
{
	DestroyNode(root);
}

void Tree::DestroyNode(TreeNode* node)
{
	TreeNode* child = NULL;
	TreeNode * brother = NULL;
	if (node == NULL)
	{
		return;
	}
	
	child = node->child;
	brother = node->nextBrother;
	delete node;
	node = NULL;
	DestroyNode(child);
	DestroyNode(brother);
}

int main()
{
	map<int, map<char, char>> data;
	data[0].insert(pair<char, char>('A', 'B'));
	data[1].insert(pair<char, char>('A', 'C'));
	data[2].insert(pair<char, char>('A', 'D'));
	data[3].insert(pair<char, char>('B', 'E'));
	data[4].insert(pair<char, char>('B', 'F'));
	data[5].insert(pair<char, char>('C', 'G'));
	data[6].insert(pair<char, char>('D', 'H'));
	data[7].insert(pair<char, char>('D', 'I'));
	data[8].insert(pair<char, char>('D', 'J'));
	data[9].insert(pair<char, char>('E', 'K'));
	data[10].insert(pair<char, char>('E', 'L'));
	data[11].insert(pair<char, char>('H', 'M'));
	Tree t;
	t.CreateTree(data); 
	// t.DestroyNode(t.root); 测试是否删除
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zbbzb/article/details/82973618