树(一):基本知识

概念:

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

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

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

特点:

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

表示方式:

  1. 树形表示法
    在这里插入图片描述
  2. 文氏图表示法
  3. 凹入表示法
    在这里插入图片描述
  4. 括号表示法
    以存储方式的图为例子:A(B(E(K,L),F),C(G),D(H(M),I,J))

基本术语:

  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. 树中节点数 等于 所有节点的度数之和 + 1
    下图中每个数字代表此节点的度,即 3 + 2 + 1 + 1(根节点) = 7
    在这里插入图片描述

  2. 度为m的树中第i层上最多有mi-1 (i >=1)个节点
    度为m的树则至少一个节点有m个子节点,最多则是每个节点下有m个子节点

    在这里插入图片描述

  3. 高度为i的次树最多有 m i − 1 m − 1 \frac{m ^i - 1 }{m-1} m1mi1 个节点
    也就是每层节点相加Sn = 1 + m1 + m2 + … + mi-1 (1)
    再简化:
    m * Sn = m + m2 + m3 + … + mi (2)
    (2) - (1) : (m - 1) Sn= mi - 1
    ∴ \therefore Sn = m i − 1 m − 1 \frac{m ^i -1 }{m-1} m1mi1

  4. 具有n个节点的m次树的最小高度为 ⌈ l o g m ( n ( m − 1 ) + 1 ) ⌉ \left\lceil\\log_m(n(m - 1) +1)\right\rceil logm(n(m1)+1)
    最小高度即每个节点的度最好都要到 m 个,才能保证最小高度
    假设n个节点m次树的高度为i,假设前 i-1 层都是满的,那么 i 层就可能满,但也能不满
    m i − 1 − 1 m − 1 + 1 ≤ n ≤ m i − 1 m − 1 \frac{m ^{i-1}-1 }{m-1} +1 \leq n \leq \frac{m ^ i -1 }{m-1} m1mi11+1nm1mi1
    简化:
    方便计算简化: m i − 1 − 1 m − 1 &lt; n ≤ m i − 1 m − 1 \frac{m ^{i-1} -1}{m-1} &lt; n \leq \frac{m ^i-1 }{m-1} m1mi11<nm1mi1
    均乘以(m - 1): m i − 1 &lt; n ( m − 1 ) + 1 ≤ m i m^{i-1} &lt; n(m-1) +1 \leq m^i mi1<n(m1)+1mi
    取m为底对数: i − 1 &lt; l o g m ( n ( m − 1 ) + 1 ) ≤ i i - 1 &lt;log_m(n(m-1)+1) \leq i i1<logm(n(m1)+1)i
    ∴ \therefore l o g m ( n ( m − 1 ) + 1 ) ≤ i &lt; l o g m ( n ( m − 1 ) + 1 ) + 1 log_m(n(m-1) + 1) \leq i &lt;log_m(n(m-1)+1) +1 logm(n(m1)+1)i<logm(n(m1)+1)+1
    ∵ \because 高度i只能去整数
    ∴ \therefore i = ⌈ l o g m ( n ( m − 1 ) + 1 ) ⌉ \left\lceil\\log_m(n(m - 1) +1)\right\rceil logm(n(m1)+1)

遍历:

  1. 先根遍历:
    (1). 访问根节点
    (2). 从左往右的顺序先根遍历所有子节点
    以存储方式的图为例子:A B E K L F C G D H M I J
  2. 后根遍历:
    (1). 从左往右的顺序后根遍历所有子节点
    (2). 访问根节点
    以存储方式的图为例子:K L E F B G C M H I J D A
  3. 层次遍历:
    从根节点从上往下, 从左往右访问节点
    以存储方式的图为例子:A B C D E F G H I J K L M

存储方式:

在这里插入图片描述

  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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值