32_Python数据结构——树与二叉树

本文介绍了树和二叉树的基本概念、术语、种类及应用场景。树的种类包括无序树、有序树,如二叉树、完全二叉树、AVL树、二叉查找树等。二叉树的特性、节点表示、树的创建和遍历方法(深度优先和广度优先)也进行了详细阐述。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、树与树算法

1、树的概念

树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。
它具有以下特点:
(1)每个节点有零个或多个子节点
(2)没有父节点的节点称为根结点
(3)每一个非根节点有且只有一个父节点
(4)除了根结点外,每个节点可以分为多个不相交的子树

2、树的术语

节点的度:一个节点含有的子树的个数称为该节点的度
树的度:一棵树中,最大的节点的度称为树的度
叶节点或终端节点:度为零的节点
父亲节点或父节点:若一个节点含有子节点,则称这个节点称为其子节点的父节点
孩子节点或子节点:一个节点含有的子树的根结点称为该结点的子节点
兄弟节点:具有相同父节点的节点互称兄弟节点

节点的层次:从根开始定义起,根为第一层,根的子节点为第二层,以此类推
树的高度或深度:树中节点的最大层次
在这里插入图片描述

3、树的种类

【1】无序树
树中任意节点的子节点之间没有顺序关系,称为无序树,自由树
【2】有序树

树中的任意节点的子节点之间有顺序关系

(1)二叉树
每个节点最多含有两个子树的树
(2)完全二叉树
对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其他各层的节点数目均以达最大值,且第d层所有节点从左向右连续地紧密排列
其中满二叉树的定义是所有的叶节点都在最底层的完全二叉树
(3)平衡二叉树(AVL树)
当且仅当任何节点的两颗子树的高度差不大于1的二叉树

(4)排序二叉树(二叉查找树)『Binary Search Tree』
又称二叉搜索树,有序二叉树
(5)霍夫曼树(用于信息编码)
带权路径最短的二叉树
(6)B树
一种对读写操作进行优化的自平衡的二叉查找树,能保持数据有序,拥有多余两个子树

4、树的储存与表示

顺序储存:将数据结构储存在固定的数组中,然后在遍历速度上有一定的优势,但因此所占空间比较大,是非主流二叉树。
二叉树通常以链式储存。

链式储存:
在这里插入图片描述

5、常见的一些树的应用场景

(1)xml,html等,编写这些东西的解析器的时候,不可避免用到树
(2)路由协议就使用了树的算法
(3)mysql数据库索引
(4)文件系统的目录结构

二、二叉树

1、概念:

二叉树是每个节点最多有两个子树的树结构。通常子树被称作左子树lchild ,右子树rchild

2、性质:

(1)在二叉树的第i层上至多有2^(i-1)个节点
(2)深度为k的二叉树至多有2^k-1个节点
(3)对于任意一颗二叉树,如果其叶子节点数为N0.而度为2的节点总数为N2,N0=N2+1
(4)具有n个结点的完全二叉数的深度必为log2(n+1)
(5)对于完全二叉数,若从上至下,从左至右编号,则编号为i的节点,其左孩子编号必为2i,其右孩子编号必为2i+1,
其双亲的编号必为i/2.

3、二叉数的节点表示以及树的创建

class Node(object):
    """二叉树节点对象的封装"""
    def __init__(self,element):
        self.element =element
        self.lchild = None
        self.rchild =None

    def __str__(self):
        """是打印的节点更好的展示出来"""
        return '<Node:%d>'%(self.element)

class BinarySortTree(object):
    """e二叉排序树的封装"""
    def __init__(self):
        self.root =None

    def is_empty(self):
        return self.root is None

    def add(self,item):
        """树里面插入元素
            1. 先判断树是否为空, 直接让根结点指向新的节点
            2. 如果不为空:
                从根结点开始访问, 判断一下item和节点的大小;
                    如果大于节点元素, 往右孩子节点添加;
                    如果小于节点元素, 往左孩子节点添加;
        """
        node =Node(item)
        if self.root is None:
            self.root = node
        bt = self.root
        while True:
            rootItem =bt.element
            #判断添加的元素是否大于根结点
            if item > rootItem:
                #如果根的右子树为空,直接添加节点到右子树即可
                if bt.rchild is None:
                    bt.rchild = node
                # 如果根结点的右子树不为空, 将右子树节点作为新的根结点, 循环继续判断;;
                bt =bt.rchild

            elif item <rootItem:
                if bt.lchild is None:
                    bt.lchild =node
                bt =bt.lchild
            # 如果插入的元素和根结点相等, 不做操作;
            else:
                return

    def breadth_travel(self):
        """
        利用队列实现树的层次遍历
        :return:
        """
        if not self.root:
            return

        else:
            queue =[]
            queue.append(self.root)
            while queue:
                node =queue.pop(0)
                print(node.element,end=',')
                if node.lchild:
                    queue.append(node.lchild)
                if node.rchild:
                    queue.append(node.rchild)
            print()

    def search(self,root,key):
        """搜索指定元素是否在树里面
        key:用户搜索的元素"""
        if root in None:
            return False
        # 如果找到节点元素和用户搜索的值相等, 直接返回节点对象
        if root.element ==key:
            return root
        elif root.element >key:
            return self.search(root.lchild,key)
        else:
            return self.search(root.rchild,key)

    def searchDetail(self,root,parent,key):
        """
        搜索指定元素是否在树里面, 如果有, 则
        返回3个值:
            1. Bool: 是否找到该元素;
            2. node: 找到元素对应的节点
            3. parent: 找到的元素对应的父节点;

        """
        if root is None:
            return False,root,parent

        if root.element ==key:
            return True,root,parent
        elif root.element >key:
            return self.searchDetail(root.lchild,root,key)
        else:
            return self.searchDetail(root.rchild,root,key)

    def delete(self, key):
        """删除二叉排序树的节点元素:
            1). 如果要删除的节点是叶子,直接删;
            2). 如果只有左子树或只有右子树,则删除节点后,将子树链接到父节点即可;
            """
        isExists,node,parent =self.searchDetail(self.root,None,key)

        if not isExists:
            print("要删除的元素%d不存在"%(key))
            return
        if node== self.root:
            print("不能删除根节点")
            return
        # 1). 如果要删除的节点是叶子,直接删;
        if node.lchild is None and node.rchild is None:
            if parent.lchild ==node:
                parent.lchild =None
            else:
                parent.rchild =None
        # 2). 如果只有左子树或只有右子树,则删除节点后,将子树链接到父节点即可;
        #只有左子树
        if node.lchild is not None and node.rchild is None:
            if parent.lchild ==node:
                parent.lchild =node.lchild
            else:
                parent.rchild =node.lchild
        #只有右子树
        if node.lchild is None and node.rchild is  not None:
            if parent.lchild ==node:
                parent.lchild = node.rchild
            else:
                parent.rchild =node.rchild
        # 3).如果有左右子树
        # 方法一: 令结点 node 的左子树为其双亲结点的左子树;
        # 结点 node的右子树为其自身直接前驱结点的右子树
        if  node.lchild is not None and node.rchild is not None:
            # 如何找到node的直接前驱节点, 找到后, 将直接前驱节点的右子树指向node的右子树;
            # 当前节点左子树的最右节点
            # 分类讨论, 删除的是父节点的左孩子还是右孩子
            if parent.lchild ==node:
               parent.lchild = node.lchild
            else:
                parent.rchild = node.lchild

            prevNode = node.lchild
            while prevNode.rchild:
                prevNode =prevNode.rchild
            # prev指的是node节点的直接前驱(中徐遍历时,node节点前面的节点)
            prevNode.rchild = node.rchild

4、二叉树的遍历

树的遍历是树的一种重要的运算,所谓遍历是指对树中所有节点的信息的访问,即依次对树中每个节点访问一次且仅访问一次,我们把这种对所有节点的访问称为遍历(traversal)
树的两种重要的遍历模式是深度优先遍历和广度优先遍历。
深度优先一般用递归,广度优先一般用队列。

深度优先遍历(Depth First Search)

【1】先序遍历

    def preorder(self,root):
        """先序遍历:根-左-右"""
        if root == None:
            return
        print(root.element,end=',')
        self.preorder(root.lchild)
        self.preorder(root.rchild)

【2】中序遍历

    def inorder(self,root):
        """中序遍历:左-根-右"""
        if root == None:
            return
        self.inorder(root.lchild)
        print(root.element, end=', ')
        self.inorder(root.rchild)

【3】后序遍历

    def lastorder(self,root):
        """后序遍历:左 -右-根"""
        if root == None:
            return
        self.lastorder(root.lchild)
        self.lastorder(root.rchild)
        print(root.element, end=', ')

在这里插入图片描述

广度优先遍历(层次遍历)

从树的root开始,从上到下从左到右遍历整个树的节点

    def breadth_travel(self):
        """
        利用队列实现树的层次遍历
        :return:
        """
        if not self.root:
            return

        else:
            queue =[]
            queue.append(self.root)
            while queue:
                node =queue.pop(0)
                print(node.element,end=',')
                if node.lchild:
                    queue.append(node.lchild)
                if node.rchild:
                    queue.append(node.rchild)
            print()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值