树模板总结

简介: 树模板总结

文章目录

树相关概念

1. 总体架构


相关术语

①结点:包含一个数据元素及若干指向子树分支的信息 。

②结点的度:一个结点拥有子树的数目称为结点的度 。

③叶子结点:也称为终端结点,没有子树的结点或者度为零的结点 。

④分支结点:也称为非终端结点,度不为零的结点称为非终端结点 。

⑤树的度:树中所有结点的度的最大值 。

⑥结点的层次:从根结点开始,假设根结点为第1层,根结点的子节点为第2层,依此类推,如果某一个结点位于第L层,则其子节点位于第L+1层 。

⑦树的深度:也称为树的高度,树中所有结点的层次最大值称为树的深度 。

⑧有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树 。

⑨无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树 。

⑩森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根结点删除,则该树就变成了一片森林,森林中的树由原来根结点的各棵子树构成 。

2.二叉树的分类

  • 完全二叉树
  • 完全二叉树的特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。需要注意的是,满二叉树肯定是完全二叉树,而完全二叉树不一定是满二叉树。
  • 完全二叉树判定
    算法思路
    判断一棵树是否是完全二叉树的思路
    1>如果树为空,则直接返回错
    2>如果树不为空:层序遍历二叉树
    2.1>如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列;
    2.1>如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;
    2.2>如果遇到一个结点,左孩子不为空,右孩子为空,或者左右孩子都为空, 且该节点之后的队列中的结点都为叶子节点,那么该树是完全二叉树,否则就不是完全二叉树;
  • 平衡二叉树
  • 表现特征:平衡树(Balance Tree,BT) 指的是,任意节点的子树的高度差都小于等于1。

3. 模板代码

C语言版本左孩子右兄弟建树

#include<iostream>
#include<cstdio>
#define maxSize 100000
using namespace std;
typedef struct CSNode {
  int parent;
  int leftChild;
  int siBling;
}Node;
typedef struct save{
  Node data[maxSize];
}BT;
Node T[maxSize];
// 获取节点深度
int getD(Node node){
  int d=0;
  while(node.parent!=-1) {
    d++;
    node = T[node.parent];
  }
  return d;
}
int main()
{
  // 节点的数量
  int t;
  cin>>t;
  int flag = t;
  // 初始化每个子节点的父节点为 -1 
  while(flag--){
    T[flag].parent = -1;
    T[flag].leftChild = T[flag].siBling = -1;
  }
  // 输入节点信息
  for(int k=0; k<t; k++){
    // 父节点
    int par;
    // 节点所拥有的孩子数量
    int total;
    cin>>par>>total;
    int c,s=-1;
    for(int i=0; i<total; ++i){
      cin>>c;
      T[c].parent=par;
      if(i==0){
        // 第一个元素为左孩子
        T[par].leftChild = c;
      }else{
        // 其余的元素为T[s]的兄弟
        T[s].siBling = c;
      }
//      切换节点, 左孩子右兄弟 
      s=c;
    } 
  }
   // 根节点
  int root;
  for(int j=0; j<t; ++j){
    if(T[j].parent == -1 ) root = j;
  }
  for(int i=0; i<t; i++){
    string type;
    if(i==root) type="root";
    else{
      if(T[i].leftChild == -1) type="leaf";
      else type = "internal node";
    }
    cout<<"node "<<i<<": parent = " <<T[i].parent<<", depth = "<<getD(T[i])<<", "<<type<<", [";
   // 从子结点的最左边开始遍历 
  int c = T[i].leftChild; 
  while (c != -1) {
    printf("%d", c); 
    if (T[c].siBling != -1) printf(", "); 
    // 跳到右侧紧邻的兄弟结点 
    c = T[c].siBling; 
  }
  cout<<"]"<<endl;
  }
  return 0;
}

C 语言版本(二叉树搜索)

#include<iostream>
using namespace std;
#define maxSize 25
typedef struct BinaryTree{
  int parent;
  int lchild,rchild;
}BT;
BT bt[maxSize];
string gettype(BT obj){
  string type;
  if( obj.parent == -1) type="root";
  else if(obj.lchild == -1 && obj.rchild == -1 ) type = "leaf";
  else type = "internal node" ;
  return type;
}
int getsibling(BT obj, int cur, bool flag){
  if(flag){
    return -1;
  }
  if( bt[obj.parent].lchild == cur ) return bt[obj.parent].rchild;
  else if( bt[obj.parent].rchild == cur)return bt[obj.parent].lchild;
  else return -1;
}
int getdegree(BT o){
  int te = 0;
  if(o.lchild != -1 ) te++;
  if(o.rchild != -1) te++;
  return te;
}
int getdp(BT o)
{
  int de = 0; 
  while(o.parent != -1 ) {
    de++;
    o = bt[o.parent];
  } 
  return de;
}
// 递归求高度
int getH( int u ){
  int h1=0;
  int h2=0;
  if(bt[u].lchild != -1 ) h1 = getH(bt[u].lchild) +1;
  if(bt[u].rchild != -1 ) h2 = getH(bt[u].rchild) +1;
  return h1>h2?h1:h2;
}
void print(BT o, int mm){
  int sibling;
  string type;
  type = gettype(bt[mm]);
  if(type == "root") sibling = getsibling(bt[mm] , mm, true) ;
  else sibling = getsibling(bt[mm] , mm, false) ;
  cout<<"node "<<mm<<": parent = "<< bt[mm].parent
    << ", sibling = "<< sibling << ", degree = " << getdegree(bt[mm])
    << ", depth = " << getdp(bt[mm]) << ", height = " << getH( mm ) <<", " << type <<endl;
}
int main()
{
  int t; cin>>t;
  // 节点初始化
  for(int i = 0; i < t; ++i){
    bt[i].parent = bt[i].lchild = bt[i].rchild = -1;
  }
  // 输入
  for(int j = 0; j < t; ++j){
    int a,b,c; cin >> a >> b >> c;
    bt[a].lchild = b;
    bt[a].rchild = c;
    bt[b].parent = a;
    bt[c].parent = a;
  }
  for(int m = 0; m < t; ++m){
    print(bt[m],m);
  }
  cout<<endl;
  return 0;
}

C语言版本的二叉树遍历

// 二叉树的遍历
#include<iostream>
#define maxSize 25
using namespace std;
typedef struct{
  int parent;
  int l;
  int r;
}Node;
Node no[maxSize];
void preOrder(int t){
  if(t == -1) return;
  cout<<' ' << t;
  preOrder(no[t].l);
  preOrder(no[t].r);
}
void inOrder(int t){
  if(t == -1) return;
  inOrder(no[t].l);
  cout <<' '<< t ;
  inOrder(no[t].r);
}
void posOrder(int t){
  if(t == -1) return;
  posOrder(no[t].l);
  posOrder(no[t].r);
  cout <<' '<< t ;
}
int main()
{
  int n; cin>>n;
  int root;
  for(int i=0; i<n; ++i) no[i].parent = no[i].l = no[i].r = -1;
  for(int i = 0; i < n; ++i){
    int a,b,c;
    cin >> a >> b >> c;
    no[a].l = b;
    no[a].r = c;
    no[b].parent = no[c].parent = a;
  }
  for(int i=0; i<n; ++i){
    if(no[i].parent == -1 ) {root = i;break;} 
  }
  cout<<"Preorder"<<endl;
  preOrder(root);
  cout<<endl;
  cout<<"Inorder"<<endl;
  inOrder(root);
  cout<<endl;
  cout<<"Postorder"<<endl;
  posOrder(root);
  cout<<endl;
  return 0;
}

C++版本二叉树模板(二叉链表建树方法)

#include<iostream>
#include<cstring>
using namespace std;
class BiTreeNode{
  public:
    char data;
    BiTreeNode *lChild;
    BiTreeNode *rChild;
    BiTreeNode():lChild(NULL),rChild(NULL){};
    ~BiTreeNode(){};
};
class BiTree{
  private:
    BiTreeNode *root;
    int pos;          // pos方便利用字符串进行建树 
    string strTree;       // 前序遍历的结果字符串,用于建树 
    BiTreeNode * createBiTree();
    void preOrder(BiTreeNode *t);
    void inOrder(BiTreeNode *t);
    void postOrder(BiTreeNode *t);
  public:
    BiTree(){};
    ~BiTree(){};
    void createTree(string treeArray);  // 利用前序遍历的结果建树 
    void preOrder();          // 开放接口  
    void inOrder();
    void postOrder(); 
};
void BiTree::createTree(string treeArray){
  pos = 0;
  strTree.assign(treeArray);
  root = createBiTree();
}
// 利用先序遍历的结果进行  递归建树 
BiTreeNode* BiTree::createBiTree(){
  BiTreeNode *T;
  char ch;
  ch = strTree[pos++];
  if(ch=='0'){
    T = NULL;
  }
  else{
    T = new BiTreeNode(); 
    T->data = ch;         // 生成根节点 
    T->lChild = createBiTree();   // 构建左子树 
    T->rChild = createBiTree();   // 构建右子树 
  }
  return T;
}
void BiTree::preOrder(){
  preOrder(root);
}
void BiTree::preOrder(BiTreeNode *t){
  if(t!=NULL){
    cout<<t->data<<' ';
    preOrder(t->lChild);
    preOrder(t->rChild);
  } 
}
void BiTree::inOrder(){
  inOrder(root);
}
void BiTree::inOrder(BiTreeNode *t){ 
  if(t!=NULL){
    inOrder(t->lChild);
    cout<<t->data<<' ';
    inOrder(t->rChild);
  } 
}
void BiTree::postOrder(){
  postOrder(root);
}
void BiTree::postOrder(BiTreeNode *t){
    if(t!=NULL){
    postOrder(t->lChild);
    postOrder(t->rChild);
    cout<<t->data<<' ';
  } 
}
int main(){
  int Nt;
  cin >> Nt;
  while(Nt--){
    string s;
    cin >> s;
//    BiTree bt();
    BiTree bt;
    bt.createTree(s);
    bt.preOrder();
    cout<<endl;
    bt.inOrder();
    cout<<endl;
    bt.postOrder();
    cout<<endl;
  }
}

DS二叉树——二叉树之数组存储

题目描述

二叉树可以采用数组的方法进行存储,把数组中的数据依次自上而下,自左至右存储到二叉树结点中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点就在数组中用0来表示。,如下图所示

从上图可以看出,右边的是一颗普通的二叉树,当它与左边的完全二叉树对比,发现它比完全二叉树少了第5号结点,所以在数组中用0表示,同样它还少了完全二叉树中的第10、11号结点,所以在数组中也用0表示。

结点存储的数据均为非负整数

输入

第一行输入一个整数t,表示有t个二叉树

第二行起,每行输入一个数组,先输入数组长度,再输入数组内数据,每个数据之间用空格隔开,输入的数据都是非负整数

连续输入t行

输出

每行输出一个示例的先序遍历结果,每个结点之间用空格隔开

样例输入

3 3 1 2 3 5 1 2 3 0 4 13 1 2 3 4 0 5 6 7 8 0 0 9 10

样例输出

1 2 3 1 2 4 3 1 2 4 7 8 3 5 9 10 6

解题思路

对比完全二叉树以及一般二叉树的数组发现,完全二叉树的的节点值=一般二叉树的数组索引+1 ,所以我们可以直接根据完全二叉树就行索引输出。

#include <iostream>
using namespace std;
class BiTree{
    int len;
    int *tree;
    void PreOrder(int i);
public:
    BiTree();
    ~BiTree();
    void PreOrder();
};
BiTree::BiTree() {
    cin>>len;
    tree = new int[len+1];
    for(int i=1;i<=len;i++)
        cin>>tree[i];
}
BiTree::~BiTree() {
    delete []tree;
}
void BiTree::PreOrder() {
    PreOrder(1);
    cout<<endl;
}
void BiTree::PreOrder(int i) {
    if(tree[i]!=0 && i<=len) {
        cout << tree[i]<<' ';
        PreOrder(2 * i);
        PreOrder(2 * i+1);
    }
}
int main()
{
    int t;
    cin>>t;
    while (t--)
    {
        BiTree myTree;
        myTree.PreOrder();
    }
    return 0;
}

DS二叉树——二叉树之父子结点

题目描述

给定一颗二叉树的逻辑结构如下图,(先序遍历的结果,空树用字符‘0’表示,例如AB0C00D00),建立该二叉树的二叉链式存储结构。

编写程序输出该树的所有叶子结点和它们的父亲结点

输入

第一行输入一个整数t,表示有t个二叉树

第二行起,按照题目表示的输入方法,输入每个二叉树的先序遍历,连续输入t行

输出

第一行按先序遍历,输出第1个示例的叶子节点

第二行输出第1个示例中与叶子相对应的父亲节点

以此类推输出其它示例的结果

样例输入

4 AB0C00D00 AB00C00 ABCD0000EF000 A00

样例输出

C D B A B C A A D F C E A A

解题思路

在遍历的时候,带上双亲节点的值,当遇到叶子时,直接输出叶子的值,把双亲的值入队。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
queue<char> qf;
class BiTreeNode{
  public:
    char data;
    BiTreeNode *lChild;
    BiTreeNode *rChild;
    BiTreeNode():lChild(NULL),rChild(NULL){};
    ~BiTreeNode(){};
};
class BiTree{
  private:
    BiTreeNode *root;
    int pos;          // pos方便利用字符串进行建树 
    string strTree;       // 前序遍历的结果字符串,用于建树 
    BiTreeNode * createBiTree();
    void preOrder(BiTreeNode *t, char father);
  public:
    BiTree(){};
    ~BiTree(){};
    void createTree(string treeArray);  // 利用前序遍历的结果建树 
    void preOrder();          // 开放接口  
};
void BiTree::createTree(string treeArray){
  pos = 0;
  strTree.assign(treeArray);
  root = createBiTree();
}
// 利用先序遍历的结果进行  递归建树 
BiTreeNode* BiTree::createBiTree(){
  BiTreeNode *T;
  char ch;
  ch = strTree[pos++];
  if(ch=='0'){
    T = NULL;
  }
  else{
    T = new BiTreeNode(); 
    T->data = ch;         // 生成根节点 
    T->lChild = createBiTree();   // 构建左子树 
    T->rChild = createBiTree();   // 构建右子树 
  }
  return T;
}
void BiTree::preOrder(){
  preOrder(root,root->data);
}
void BiTree::preOrder(BiTreeNode *t,char father){
  if(t!=NULL){
    if(!t->lChild && !t->rChild){
      cout<<t->data<<' ';
      qf.push(father);
    }
    preOrder(t->lChild,t->data);
    preOrder(t->rChild,t->data);
  } 
}
int main(){
  int Nt;
  cin >> Nt;
  while(Nt--){
    while(!qf.empty()){
      qf.pop();
    }
    string s;
    cin >> s;
    BiTree bt;
    bt.createTree(s);
    bt.preOrder();
    cout<<endl;
    while(!qf.empty()){
      cout<<qf.front()<<' ';
      qf.pop();
    }
    cout<<endl;
  }
  return 0;
}
相关文章
|
4月前
|
JavaScript
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
113 0
|
索引
一次区分 B树、B+树,B*树
一次区分 B树、B+树,B*树
88 0
|
6月前
线段树模板
线段树模板
44 0
60EasyUI 树形菜单- 树形网格惰性加载节点
60EasyUI 树形菜单- 树形网格惰性加载节点
37 0
|
JavaScript
使用JS递归处理树状结构数据
使用JS递归处理树状结构数据
183 0
使用JS递归处理树状结构数据
|
存储 人工智能 算法
Trie树模板与应用
Trie树模板与应用
89 0
Trie树模板与应用
|
存储
B+树的源码解析
B+树是一种常用的数据结构,用于在数据库系统和文件系统中实现有序的存储和快速的查找。它相比于传统的B树有一些优势,例如更适合在磁盘上存储数据、减少磁盘I/O次数等。在本文中,我将对B+树的源码进行解析,以帮助读者更好地理解其实现原理和使用方法。
385 0
|
存储 算法
线段树模板与练习
线段树模板与练习
100 0
|
JavaScript
树形组件(可动态添加属性、无限嵌套)及递归展示tree数据
树形组件(可动态添加属性、无限嵌套)及递归展示tree数据
树形组件(可动态添加属性、无限嵌套)及递归展示tree数据