【数据结构】|第11章:二叉树和其他树

11.1树

  • 定义
    在这里插入图片描述
  • 术语:
    • 根(root):层次中最高层的元素
    • 根的孩子(children):跟的下一级的元素
      • 是余下所有元素所构成的子树的根
    • 叶子(leaves):树中没有孩子的元素

在这里插入图片描述

  • 级(level)/层次:一个元素的级=其父母的级+1。树根的级为1.

在这里插入图片描述

  • 元素的度
    • 指其孩子的个数
    • 叶子节点 度=0

在这里插入图片描述

  • 树的度:元素度的最大

在这里插入图片描述

11.2 二叉树

在这里插入图片描述
一般,二叉树可以为空,树不能为空

  • 表达式树:
    在这里插入图片描述

11.3 二叉树的特性

  1. 包含n(n>0)个元素的二叉树的边数 n − 1 n-1 n1
  2. 二叉树高度为h且 h > = 0 h>=0 h>=0,则该二叉树最少 h h h个元素,最多 2 h − 1 2^h-1 2h1个元素
  3. 包含n(n>0)个元素的二叉树,高度最大为n,最小 [ l o g 2 ( n + 1 ) ] [log_2(n+1)] [log2(n+1)]
  1. 在这里插入图片描述
  2. 在这里插入图片描述
  3. 在这里插入图片描述

满二叉树

  • 当高度为h的二叉树恰好有 2 h − 1 2^h-1 2h1个元素时,称为满二叉树
    在这里插入图片描述
    完全二叉树(是满二叉树的一个特例)
    在这里插入图片描述
  • 当且仅当二叉树与k层满二叉树前1~n个节点所构成的二叉树结构相同时,深度为k具有n个节点的二叉树是一颗完全二叉树
  • k层完全二叉树:
    • 前k-1层为满二叉树
    • 第k层上的节点都连续排列在第k层的左端
  • 有n个元素的完全二叉树的深度为: [ l o g 2 ( n + 1 ) ] [log_2(n+1)] [log2(n+1)]
  1. 完全二叉树中一元素序号为i,1<=i<=n,则:
  • i=1,该元素为二叉树的根;若i>1,则该元素父节点的编号为 [ ( i / 2 ) ] [(i/2)] [(i/2)]
  • 2i>n,该元素无左孩子;否则,左孩子编号为 2 i 2i 2i
  • 2i+1>n,该元素无右孩子;否则,右孩子编号为 2 i + 1 2i+1 2i+1

11.4二叉树描述

11.4.1数组描述

  • 二叉树元素按照其编号存储在数组的相应位置,可以看作是缺少了部分元素的完全二叉树
  • 一个有n个元素的二叉树需要存储空间: n + 1 n+1 n+1~ 2 n 2^n 2n (或n~ 2 n − 1 2^n-1 2n1 )
  • 右斜二叉树存储空间最大
    在这里插入图片描述

11.4.2链表描述

在这里插入图片描述
在这里插入图片描述

链表二叉树的节点结构

template <class T>
struct binaryTreeNode
{
    T element;
    binaryTreeNode<T> *leftChild, // 指向左孩子节点的指针
        *rightChild;              // 指向右孩子节点的指针
    // 3个构造函数
    binaryTreeNode() // 没有参数
    {
        leftChild = rightChild = nullptr;
    }
    binaryTreeNode(const T &theElement) // 只有数据参数
    {
        element(theElement);
        leftChild = rightChild = nullptr;
    }
    binaryTreeNode(const T &theElement, // 数据 + 指针参数
                   binaryTreeNode *theLeftChild,
                   binaryTreeNode *theRightChild)
    {
        element(theElement);
        leftChild = theLeftChild;
        rightChild = theRightChild;
    }
};

10.5二叉树常用操作

在这里插入图片描述

10.6二叉树遍历

  • 许多二叉树操作是通过对二叉树进行遍历来完成
  • 在二叉树的遍历中,每个元素都被访问到且仅被访问一次
  • 在访问时执行对该元素的相应操作(复制、删除、输出等)
  • 遍历方法:
    在这里插入图片描述

在这里插入图片描述

前序遍历

template <class E>
void preOrder(binaryTreeNode<E> *t)
{ // 前序遍历二叉树 *t
    if (t != nullptr)
    {
        visit(t);                // 访问根节点
        preOrder(t->leftChild);  // 前序遍历左子树
        preOrder(t->rightChild); // 前序遍历右子树
    }
}

中序遍历

template <class E>
void inOrder(binaryTreeNode<E> *t)
{ // 中序遍历二叉树*t
    if (t != nullptr)
    {
        inOrder(t->leftChild);  // 中序遍历左子树
        visit(t);               // 访问根节点
        inOrder(t->rightChild); // 中序遍历右子树
    }
}

  • 输出的表达式具有歧义性
  • 前缀表达式:操作符位于操作数之前,操作数从左到右顺序出现
  • 后缀表达式:操作符跟在操作数之后,操作数从左到右顺序出现
  • 使用括号来避免歧义
    • 每个操作符用括号括起来
    • 每个操作数和操作符使用括号括起来

在这里插入图片描述

  • 输出完全括号化的中缀表达式
template <class E>
void infix(binaryTreeNode<E> *t)
{ // 输出表达式的中缀形式
    if (t != nullptr)
    {
        cout << '(';
        infix(t->leftChild);  // 左操作数
        cout << t->element;   // 操作符
        infix(t->rightChild); // 右操作数
        cout << ')';
    }
}

后序遍历

template <class E>
void postOrder(binaryTreeNode<E> *t)
{ // 后序遍历二叉树*t
    if (t != nullptr)
    {
        postOrder(t->leftChild);  // 后序遍历左子树
        postOrder(t->rightChild); // 后序遍历右子树
        visit(t);                 // 访问根节点
    }
}

层次遍历

在这里插入图片描述

template <class E>
void levelOrder(binaryTreeNode<E> *t)
{ // 层次遍历二叉树*t
    arrayQueue<binaryTreeNode<E> *> q;
    while (t != NULL)
    {
        visit(t); // 访问t
        // 将t的左右孩子放入队列
        if (t->leftChild)
            q.push(t->leftChild);
        if (t->rightChild)
            q.push(t->rightChild);
        try
        {
            t = q.front(); // 访问下一个节点
        }
        catch (queueEmpty)
        {
            return;
        }
        q.pop();
    }
}

例题:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

遍历算法性能

在这里插入图片描述

11.7抽象数据类型binaryTree

抽象数据类型 binaryTree {
	实例:
		元素集合;如果不空,则被划分为根、左子树和右子树;每个子树仍是一个二叉树
	操作:
		empty(): 如果二叉树为空,则返回true,否则返回false
		size(): 返回二叉树的节点/元素个数
		preorder(visit): 前序遍历二叉树,visit是访问函数
		inOrder(visit): 中序遍历二叉树
		postOrder(visit): 后序遍历二叉树
		levelOrder(visit): 层次遍历二叉树
}

void( * )(T * )是一种函数类型,返回值类型为void,参数类型为T*

template <class T>
class binaryTree
{
public:
    virtual ~binaryTree() {}
    virtual bool empty() const = 0;
    virtual int size() const = 0;
    virtual void preOrder(void (*visit)(T *)) = 0; // 参数为函数指针
    virtual void inOrder(void (*)(T *)) = 0;
    virtual void postOrder(void (*)(T *)) = 0;
    virtual void levelOrder(void (*)(T *)) = 0;
};

11.8类linkedBinaryTree

template <class E>
class linkedBinaryTree : public binaryTree<binaryTreeNode<E>>
{
private:
    binaryTreeNode<E> *root; // 指向根的指针
    int treeSize;//数的节点个数
    static void (*visit)(binaryTreeNode<E> *);              // 指针变量,指向一个函数
    static void preOrder(binaryTreeNode<E> *t);             // static代表类的静态函数
    static void inOrder(binaryTreeNode<E> *t);              // 不需实例化即可调用
    static void postOrder(binaryTreeNode<E> *t);            // 不能使用对象变量
    static void dispose(binaryTreeNode<E> *t) { delete t; } // 删除t指向的节点
public:
    linkedBinaryTree()
    {
        root = nullptr;
        treeSize = 0;
    }
    ~linkedBinaryTree() { erase(); }
    bool empty() const { return treeSize == 0; }
    // 设置好theVisit函数,前序遍历所有节点,并对每个节点调用theVisit函数
    void preOrder(void (*theVisit)(binaryTreeNode<E> *))
    {
        visit = theVisit;
        preOrder(root);
    }
    void inOrder(void (*theVisit)(binaryTreeNode<E> *))
    {
        visit = theVisit;
        inOrder(root);
    }
    void postOrder(void (*theVisit)(binaryTreeNode<E> *))
    {
        visit = theVisit;
        postOrder(root);
    }
    void levelOrder(void (*)(binaryTreeNode<E> *));
    void erase()
    { // 使用后序遍历删除所有节点
        postOrder(dispose);
        root = nullptr;
        treeSize = 0;
    }
};

私有前序遍历函数

template <class E>
void linkedBinaryTree<E>::preOrder(binaryTreeNode<E> *t)
{
    if (t != nullptr)
    {
        linkedBinaryTree<E>::visit(t); // 访问根节点,调用静态函数指针指向的函数
        preOrder(t->leftChild);        // 前序遍历左子树
        preOrder(t->rightChild);       // 前序遍历右子树
    }
}

输出

template <class E>
class linkedBinaryTree : public binaryTree<binaryTreeNode<E>>
{
private:
    …… static void output(binaryTreeNode<E> *t) { cout << t->element << ‘ ‘; }

public:
    …… void preOrderOutput()
    {
        preOrder(output);
        cout << endl;
    }
    void inOrderOutput()
    {
        inOrder(output);
        cout << endl;
    }
    void postOrderOutput()
    {
        postOrder(output);
        cout << endl;
    }
    void levelOutput()
    {
        levelOrder(output);
        cout << endl;
    }
};

计算高度

template <class E>
class linkedBinaryTree : public binaryTree<binaryTreeNode<E>>
{
private:
    …… int height(binaryTreeNode<E> *t) const;

public:
    …… int height() const { return height(root); }
};


template <class E>
int linkedBinaryTree<E>::height(binaryTreeNode<E> *t) const
{
    if (t == nullptr) // 叶子节点再下一层
        return 0;
    int hl = height(t->leftChild);  // 左子树的高度
    int hr = height(t->rightChild); // 右子树的高度
    if (hl > hr)
        return ++hl;
    else
        return ++hr;
}

11.9应用

11.9.1设置信号放大器

在这里插入图片描述
在这里插入图片描述

  • 求解策略
    在这里插入图片描述
    在这里插入图片描述

放置放大器和计算degradeToLeaf的伪代码

degradeToLeaf(i) = 0;
for (j in children(i))
{
    if (degradeToLeaf(j) + degradeFromParent(j) > 容忍值)
    {
        在 j 放置放大器;
        degradeToLeaf(i) = max(degradeToLeaf(i), degradeFromParent(j));
    }
    else
    {
        degradeToLeaf(i) = max(degradeToLeaf(i), degradeToLeaf(j) +
                                                     degradeFromParent(j));
    }
}
  • 树的二叉树描述
    在这里插入图片描述

  • 森林的二叉树表示
    在这里插入图片描述

  • 二叉树转换为树
    在这里插入图片描述

  • 二叉树转换为森林
    在这里插入图片描述

并查集

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

void initialize(int numberOfElements)
{ // 初始化,每个元素是一个单独的树,的父节点为空
    parent = new int[numberOfElements + 1];
    for (int e = 1; e <= numberOfElements; e++)
        parent[e] = 0;
}
int find(int theElement)
{ // 返回包含theElement的树的根节点
    while (parent[theElement] != 0)
        theElement = parent[theElement]; // 上移一层
    return theElement;
}
void unite(int rootA, int rootB)
{ // 将根为rootA 和rootB的两棵树进行合并
    parent[rootB] = rootA;
}

  • 时间复杂性
    在这里插入图片描述
    在这里插入图片描述
  • 性能改进
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值