大师兄的数据结构学习笔记(五):二叉树

大师兄的数据结构学习笔记(四):树结构
大师兄的数据结构学习笔记(六):树的应用

一、什么是二叉树(Binary Tree)

1. 二叉树的定义
  • 二叉树T是一个有穷的结点集合,这个集合可以为空。
  • 若不为空,则它由根结点左子树T_L右子树T_R的两个不相交的二叉树组成。
  • 可以将二叉树理解为一个有左右之分的度为二的树。
2. 二叉树的五种基本形态

1) 空二叉树(什么都没有,nothing)


2) 只有一个根结点的二叉树(左右子树为空)

3) 右子树为空的二叉树(右腿断了)

4) 左子树为空的二叉树(左腿断了)

5) 左右子树都非空的的二叉树(既有左子树又有右子树,)

3. 特殊二叉树

1) 斜二叉树(Skewed Binary Tree)

  • 所有的子树都是左子树或右子树。
  • 相当于链表。


2) 完全二叉树(Full Binary Tree)

  • 除了叶结点,每个结点都有两个子树。
  • 叶结点都靠左对齐。


3) 完美二叉树(Perfect Binary Tree)

  • 除了叶结点,每个结点都有两个子树。
  • 叶结点全在同一层。


4. 二叉树的重要性质
  • 二叉树第i层的最大结点数为2^{i-1},i>=1
  • 深度为k的二叉树的最大结点总数为2^k-1,k>=1
  • 任何非空二叉树T,若n_0表示叶结点的个数、n_2是度为2的非叶结点个数,那么两者满足关系n_0=n_2+1

二、实现二叉树

1. 二叉树的抽象数据类型
  • 操作集: BT \in BinTree, Item \in ElementType
  • 重要操作:

1) Boolean IsEmpty(BinTree BT) 判别BT是否为空。
2) void Traversal(BinTree BT) 按顺序遍历每个结点。
3) BinTree CreatBinTree() 创建二叉树。

2. 二叉树的遍历方法
名称 顺序
先序(Pre Order Traversal) 根->左子树->右子树
中序(In Order Traversal) 左子树->根->右子树
后序(Post Order Traversal) 左子树->右子树->根
层次遍历(Level Order Traversal) 从上到下,从左到右
3. 二叉树的存储结构
3.1 顺序存储结构
  • 完全二叉树按从上至下、从左到右的顺序存储n个结点的完全二叉树的结点父子关系。
  • 非完全二叉树可以通过补充空结点的方式成为完全二叉树。
  • 非根结点(序号i>1)的父结点的序号是i/2
  • 结点(序号为i)的左儿子结点的序号是2i(若2i<=n,否则没有左儿子)。
  • 结点(序号为i)的左儿子结点的序号是2i+1(若2i+1<=n,否则没有左儿子)。
3.2 链表存储结构
  • 用左右两个指针表示左右子树。


#ifndef BTREE_H
#define BTREE_H

template<typename T>
struct BinTreeNode
{
    T data;                                                                 //存储的数据
    BinTreeNode<T>* leftChild, * rightChild;                                //左右子树
    BinTreeNode() :leftChild(nullptr), rightChild(nullptr) {}               //构造函数
    BinTreeNode(T x, BinTreeNode<T>* l = nullptr, 
        BinTreeNode<T>* r = nullptr):data(x),leftChild(l),rightChild(r) {}  //带参数的构造函数
};

template<typename T>
class BinaryTree
{
public:
    BinaryTree() :root(nullptr) {};                         //构造函数
    BinaryTree(T value) :RefValue(value), root(nullptr) {}; //指定结束标识的构造函数
    ~BinaryTree() { Destroy(root); }                        //析构函数
    void CreatBinTree();                                    //创建二叉树
    bool IsEmpty();                                         //判断是否为空树
    void PreOrder() { PreOrder(root); }                     //先序遍历
    void InOrder() { InOrder(root); }                       //中序遍历
    void PostOrder() { PostOrder(root); }                   //后序遍历
    void LevelOrder() { LevelOrder(root); };                    //层次遍历

private:
    BinTreeNode<typename T> *root;                          //根节点
    T RefValue;                                             //停止信号
    void PreOrder(BinTreeNode<typename T>*& subTree);       //先序遍历
    void InOrder(BinTreeNode<typename T>*& subTree);        //中序遍历
    void PostOrder(BinTreeNode<typename T>*& subTree);      //后序遍历
    void LevelOrder(BinTreeNode<typename T>*& subTree);     //层次遍历
    void Destroy(BinTreeNode<typename T>*& subTree);        //销毁树
};

#endif
#include <iostream>
#include <stack>
#include <queue>
#include"BTree.h"
using namespace std;

template<typename T>
bool BinaryTree<T>::IsEmpty()
{
    //判断是否为空树
    if (root == nullptr)
    {
        return true;
    }
    return false;
}

template<typename T>
void BinaryTree<T>::Destroy(BinTreeNode<typename T>*& subTree)
{   
    // 销毁树
    if (subTree != nullptr)
    {
        Destroy(subTree->leftChild);
        Destroy(subTree->rightChild);
        delete subTree;
        subTree = nullptr;
    }
}

template<typename T>
void BinaryTree<T>::CreatBinTree()
{
    stack < BinTreeNode<T>* > S;
    root = nullptr;
    BinTreeNode<T>* p, * t; // p用来记住当前创建的结点,t用来记住栈顶元素
    int k = 1;  //左右标记
    T ch;
    cin >> ch;
  
    while (ch != RefValue)
    {
        switch (ch)
        {
            case '(':
                S.push(p);
                k = 1;
                break;

            case ')':
                S.pop();
                break;

            case ',':
                k = 2;
                break;

            default:
                p = new BinTreeNode<T>(ch);//构造结点
       
                if (IsEmpty())
                {
                    root = p;
                }
                else if (k == 1)
                {
                    t = S.top();
                    t->leftChild = p;
                }
                else
                {
                    t = S.top();
                    t->rightChild = p;
                }
        }
        cin >> ch;
    }
}

template<typename T>
void BinaryTree<T>::PreOrder(BinTreeNode<typename T>*& subTree)
{
    //先序遍历
    if (subTree != nullptr)
    {
        cout << subTree->data << " ";
        PreOrder(subTree->leftChild);
        PreOrder(subTree->rightChild);
    }
}

template<typename T>
void BinaryTree<T>::InOrder(BinTreeNode<typename T>*& subTree)
{
    //中序遍历
    if (subTree != nullptr)
    {
        PreOrder(subTree->leftChild);
        cout << subTree->data << " ";
        PreOrder(subTree->rightChild);
    }
}

template<typename T>
void BinaryTree<T>::PostOrder(BinTreeNode<typename T>*& subTree)
{
    //中序遍历
    if (subTree != nullptr)
    {
        PreOrder(subTree->leftChild);
        PreOrder(subTree->rightChild);
        cout << subTree->data << " ";
    }
}

template<typename T>
void BinaryTree<T>::LevelOrder(BinTreeNode<typename T>*& subTree)
{
    //层次遍历
    queue<BinTreeNode<T>*> Q;
    Q.push(nullptr); //空树信号

    while (subTree != nullptr)
    {
        cout << subTree->data << " ";
        Q.pop();
        
        if (subTree->leftChild != nullptr)
        {
            Q.push(subTree->leftChild);
        }

        if (subTree->rightChild != nullptr)
        {
            Q.push(subTree->rightChild);
        }
    }
    cout << endl;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352