赞
踩
树(Tree)是n(n>=0)个结点的有限集。n=0时称为空树。在任意一棵非空树中满足以下两个要求:
度的概念可以根据针对树还是节点分别进行理解:
我们从根开始定义起,根为第1层,根的子节点为第2层,以此类推将树进行分层。如下图:
在不同的书籍中对于这部分的定义各不相同,我们理解以下这两个定义的含义即可。
对于节点而言
- 节点的高度:节点到最远叶子节点的最长路径上边的数量。叶子节点高度为0。
- 节点的深度:节点到根节点的路径上边的数量。所有根节点深度为0。
对于树而言
- 树的高度:树的高度等于根节点的高度,等于最远叶子节点的深度。
- 树的深度:树的深度等于树的高度。
- 树的宽度:两个最长路径的叶子节点之间节点数。
我们根据子节点的数量可以将树分为二叉树和多叉树,就如定义,二叉树即是指该树上的任何一个节点最多有两个字节点。具体定义如下:
除此以外我们还可以根据树是否有序将树分为有序树和无序树。具体概念如下:
3. 有序树:节点各子树从左到右有次序(不能互换)。
4. 无序树:节点各子树从左到右无次序(能互换)。
完全二叉树(Complete Binary Tree): 每层结点都完全填满,在最后一层上如果不是满的,则只缺少右边的若干结点。如下图所示:
当断续的缺失一个节点时就不再是一棵完全二叉树,如下图所示:
满二叉树(Full Binary Tree):二叉树中的每个结点恰好有两个孩子结点且所有叶子结点都在同一层。如下图所示:
二叉树满足的性质
满二叉树的性质
完全二叉树的性质
- 如果i=1,则结点i是二叉树的根,无双亲结点;如果i>1,则其双亲结点编号是[i/2]。
- 如果2i>n:则结点i为叶子结点,无左孩子;否则,其左孩子结点编号是2i。
如果2i+1>n:则结点i无右孩子;否则,其右孩子结点编号是2i+1。
我们给出如下图的树:
然后我们使用如下所提出的表示法进行表示。
使用双亲表示法中的节点信息为:
struct Node{
char data;
int parent;
};
Node nodes[n];
使用双亲表示法比较容易找到双亲,但是不容易找到孩子。利用该方法得出表格:
使用孩子表示法中的节点信息为:
struct Node{
char data;
vector<int> children;
};
Node nodes[n];
这种方式比较容易找到孩子,但是不容易找到双亲,我们可以得到如下图表
这种方法节点中的信息如下:
struct Node{
char data;
int parent;
vector<int> children;
};
Node nodes[n];
使用这种方式我们很容易找到双亲和孩子,但是显然这种方式所占用的内存空间也更加大。我们可以得到如下的表格:
节点信息如下:
struct Node{
char data;
int firstchild;
int rightsib;
};
Node nodes[n];
这种方式显然比较容易找到孩子和兄弟,但是不容易找到双亲。
#include <iostream> #include <vector> using namespace std; // 打印多叉树 // 多叉树的表示 class Tree{ struct Node{ char data; int parent; Node(char data, int parent):data(data),parent(parent){} }; vector<Node> tree; public: int Add(char data, int parent){ tree.emplace_back(data, parent);// 直接进行移动,避免了拷贝>构造 return tree.size()-1; } void Print() const{ for(auto node:tree){ if(node.parent!=-1){ cout << tree[node.parent].data << "->" << node.data << endl; } } } }; int main(){ Tree tree; int a = tree.Add('A', -1); int b = tree.Add('B', a); int c = tree.Add('C', b); int d = tree.Add('D', b); int e = tree.Add('E', c); int f = tree.Add('F', c); tree.Add('G', d); tree.Add('H', d); tree.Add('I', d); tree.Add('J', e); tree.Print(); }
实现后得到如下结果:
相比较以上多叉树的表示方法,我们其是更常用顺序表表示二叉树,这也是二叉树特有的表示方式,因为二叉树节点之间的关系如下:
节点 | 下标 |
---|---|
根节点 | 1 |
叶子节点i | 2i > 2^k-1 |
节点i的父节点 | i/2 |
节点i的左孩子节点 | 2i |
节点i的右孩子节点 | 2i+1 |
故而当我们有如下的二叉树:
我们可以使用如下顺序表表示这个树:
相关实现代码如下:
二叉树比较常见的存储方式是链式存储方式,代码实现如下:
#include <iostream> #include <vector> using namespace std; // 打印多叉树 // 多叉树的表示 class Tree{ struct Node{ char data; Node* left = nullptr; Node* right = nullptr; Node(char data):data(data){} friend ostream& operator<<(ostream& os, const Node* node){ if(nullptr != node.left){ os << node.data << "->" << node.left->data << endl; os << *node.left; } if(nullptr != node.right){ os << node.data << "->" << node.right->data << endl; os << *node.right; } return os; } }; Node* root = nullptr; public: Node* AddLeft(char data, Node* parent){ Node* node = new Node(data); if(Null == parent) root = node; else parent->left = node; return node; } Node* AddRight(char data, Node* parent){ Node* node = new Node(data); if(Null == parent) root = node; else parent->right = node; return node; } void Print()const{ cout << *root << endl; } }; int main(){ Tree tree; auto root = tree.AddLeft('A', nullptr); auto b = tree.AddLeft('B', root); auto c = tree.AddRight('C',root); auto d = tree.AddLeft('E', b); auto e = tree.AddRight('J',e); auto f = tree.AddLeft('F', c); auto g = tree.AddRight('G',c); tree.Print(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。