数据结构与算法Python版 09 数构之树相关

树的知识什么是树树是一种基本的非线性数据结构,在操作系统、图形学、数据库系统、计算机网络等领域被广泛使用。跟自然界中的树一样,数据结构树也分为:根、枝、叶三个部分,一般数据结构的图示会把根放在上方,叶放在下方,就像一颗倒置的树,如下示例:相关术语节点(node)节点是组成树的基本部分,每个节点具有不同的名称或“键值”属性。除此之外,节点还可以保存额外数据项,数据项根据不同的应用而变化。边(edge)边是组成树的另一个基本部分,每条边恰好连接两个节点,表示节点之间具有关联。除此之外,边
摘要由CSDN通过智能技术生成

树的知识

什么是树

树是一种基本的非线性数据结构,在操作系统、图形学、数据库系统、计算机网络等领域被广泛使用。

跟自然界中的树一样,数据结构树也分为:根、枝、叶三个部分,一般数据结构的图示会把根放在上方,叶放在下方,就像一颗倒置的树,如下示例:

image-20210423175442117

相关术语

节点(node)

节点是组成树的基本部分,每个节点具有不同的名称或“键值”属性。

除此之外,节点还可以保存额外数据项,数据项根据不同的应用而变化。

image-20210423183240968

边(edge)

边是组成树的另一个基本部分,每条边恰好连接两个节点,表示节点之间具有关联。

除此之外,边还具有出入方向:

  • 每个节点(除根节点)恰好有一条来自另一节点的入边。

  • 每个节点可以有多条连到其它节点的出边。

image-20210423183637054

根(root)

根是树中唯一一个没有入边的节点,即最顶端的节点。

image-20210423183100473

路径(path)

路径是由边依次连接在一起的节点组成的有序列表,如:HTML->BODY->UL->LI就是一条路径。

image-20210423183853742

子节点(children)

入边均来自于同一个节点的若干节点,称为这个节点的子节点。

image-20210423182947004

父节点(parent)

一个节点是其所有出边所连接节点的父节点。

image-20210423182906981

兄弟节点(sibling)

具有同一个父节点的节点之间称为兄弟节点.

image-20210423182758607

子树(subtree)

子树是一个节点和其所有子孙节点,以及相关边的集合。

一个树中有多个子树,每个子树是独立的一颗树。

image-20210423181607109

叶子节点(leaf)

没有子节点的节点称为叶节点。

image-20210423182646416

层级(level)

根节点开始到达一个节点的路径,所包含的边的数量,称为这个节点的层级。

Root从0开始计数,也可以从1开始计数:

image-20210423182551238

高度(height)

树中所有节点的最大层级称为树的高度。

如下图树的高度为2:

image-20210423182307745

度(degree)

一个枝的度代表它有几条出边,而一颗树的度则取决于树中节点的最大度。

如,一颗树中最大的度为2,这可树可被称为二叉树,除此之外还有三叉、四叉树等结构。

如下图,这是一颗三叉树:

image-20210425141745353

认识二叉树

普通二叉树

普通的二叉树没什么要求,树的最大度为2即可。

image-20210621164133152

完全二叉树

在完全二叉树中,枝节点必须全部是满的,叶子节点可以不满。

但是新的节点添加时必须从左至右依次添加,不能先添加右边后添加左边。

image-20210621163836955

平衡二叉树

树的左右子树高度差不超过1的树被称为平衡二叉树,空树也是平衡二叉树的一种。

image-20210621165147344

满二叉树

满二叉树的意思就是无论是枝节点还是叶子节点,必须全部都是满的。

image-20210621165624388

二叉树表示

列表表示法

在Python中,我们可以使用多维的列表来表示一颗不确定度的多叉树。

这样的做法有一个好处,每一个列表都是一颗子树,索引值1是左子树,索引值2是右子树。

同时,如果要增加某个节点的度,则向其添加一个空列表即可。

image-20210621142201732

如上述这幅图的二叉树,则可以向下面这样进行表示:

  • 第1个元素为根节点的值
  • 第2个元素是左子树(所以也是一个列表)
  • 第3个元素是右子树(所以也是一个列表)
[root, [left], [right]]
-----------------------
   0      1       2

如下所示:

myTree = \
    [
        "a",
        ["b",
         ["d", [], []],
         ["e", [], []]
         ],
        ["c", 
         ["f"]
         ]
    ]

拿到第二层的叶子节点f:

print(myTree[2][1])

节点表示法

使用节点表示法,能够更加清晰的管理树,这比列表表示法通常更加省力。

如下图所示:

image-20210621142742404

以下是代码实现上图中二叉树的表现:

class BinaryTree:
    def __init__(self, root):
        self.key = root
        self.leftChild = None
        self.rightChild = None
        self.height = 0

    def insertLeft(self, newNode):
        tree = BinaryTree(newNode)
        if not self.leftChild:
            self.leftChild = tree
        else:
            # 如果插入位置已有节点,则整体向下挪
            # 新的子节点与旧的子节点链接,旧的父节点与新的子节点链接
            tree.leftChild = self.leftChild
            self.leftChild = tree
        self.height += 1

    def insertRight(self, newNode):
        tree = BinaryTree(newNode)
        if not self.rightChild:
            self.rightChild = tree
        else:
            tree.rightChild = self.rightChild
            self.rightChild = tree
        self.height += 1

    def getRightChild(self):
        return self.rightChild

    def getLeftChild(self):
        return self.leftChild

    def setRootVal(self, obj):
        self.key = obj

    def getRootVal(self):
        return self.key

if __name__ == '__main__':
    binaryTree = BinaryTree("a")
    binaryTree.insertLeft("b")
    binaryTree.insertRight("c")
    binaryTree.leftChild.insertLeft("d")
    binaryTree.leftChild.insertRight("e")
    binaryTree.rightChild.insertLeft("f")

二叉树遍历

将一颗二叉树依次排开,如下所示:

  • 根节点在中间
  • 左节点在左边
  • 右节点在右边
image-20210425155317927

那么就会有不同的4种遍历规则。

  • 前序遍历(preorder)
  • 中序遍历(inorder)
  • 后序遍历(postorder)
  • 层级遍历(levelorder)

我们可以在BinaryTree中新增几个实例方法,用来书写不同的遍历代码:

class BinaryTree:
    ...

    def preOrder(self):
        pass

    def inOrder(self):
        pass

    def postOrder(self):
        pass

    def levelOrder(self):
        pass

前序遍历(pre order)

前序遍历规则如下:

  • 首先访问根节点
  • 前序访问左子树
  • 前序访问右子树

一句话总结:中左右

遍历顺序:

image-20210425155546095

代码实现:

    def preOrder(self):
        def inner(tree):
            if tree:
                print(tree.getRootVal())
                inner(tree.getLeftChild())
                inner(tree.getRightChild())
        inner(self)

中序遍历(in order)

中序遍历规则如下:

  • 中序访问左子树
  • 然后访问根节点
  • 中序访问右子树

一句话总结:左中右

遍历顺序:

image-20210425155745841

代码实现:

    def inOrder(self):
        def inner(tree):
            if tree:
                inner(tree.getLeftChild())
                print(tree.getRootVal())
                inner(tree.getRightChild())
        inner(self)

后序遍历(post order)

后序遍历规则如下:

  • 后序访问左子树
  • 后序访问右子树
  • 最后访问根节点

一句话总结:左右中

遍历顺序:

image-20210425155914157

代码实现:

    def postOrder(self):
        def inner(tree):
            if tree:
                inner(tree.getLeftChild())
                inner(tree.getRightChild())
                print(tree.getRootVal())
        inner(self)

层级遍历(level order)

层级遍历没什么好说的,按层访问:

  • 第0层、根
  • 第1层、左、右
  • …第n层、左、右

遍历顺序:

image-20210425160204961

代码实现,需要借助一个双端队列或者列表:

    def levelOrder(self):
        def inner(tree):
            treeLst = []
            treeLst.append(tree)
            while len(treeLst) > 0:
                node = treeLst.pop(0)
                print(node.getRootVal())
                if node.leftChild:
                    treeLst.append(node.getLeftChild())
                if node.rightChild:
                    treeLst.append(node.getRightChild())
        inner(self)

根据遍历画出树

如果给出你2个遍历结果,并且指明这棵树是二叉树,如何画出这棵树的结构?

  • 前序遍历顺序是 A B C D E F G
  • 中序遍历顺序是 C B D A F E G

首先,前序遍历是中左右,中序遍历是左中右,按照下面的结构开始进行结构划分:

前序: [A] [B C D] [E F G]
中序: [C B D] [A] [F E G]

划分完成之后就可以出图了:

image-20210425162554727
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是七种常见的排序算法及其基本原理: 1. 冒泡排序(Bubble Sort): - 基本原理:比较相邻的两个元素,如果顺序错误则交换位置,每次循环将最大的元素移动到末尾。 - 代码示例: ```python def bubble_sort(arr): n = len(arr) for i in range(n-1): for j in range(n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr ``` 2. 选择排序(Selection Sort): - 基本原理:每次从未排序的部分选择最小的元素,放到已排序部分的末尾。 - 代码示例: ```python def selection_sort(arr): n = len(arr) for i in range(n-1): min_idx = i for j in range(i+1, n): if arr[j] < arr[min_idx]: min_idx = j arr[i], arr[min_idx] = arr[min_idx], arr[i] return arr ``` 3. 插入排序(Insertion Sort): - 基本原理:将未排序的元素逐个插入到已排序部分的正确位置。 - 代码示例: ```python def insertion_sort(arr): n = len(arr) for i in range(1, n): key = arr[i] j = i - 1 while j >= 0 and arr[j] > key: arr[j+1] = arr[j] j -= 1 arr[j+1] = key return arr ``` 4. 希尔排序(Shell Sort): - 基本原理:将待排序的元素按照一定的间隔分组,对每组使用插入排序,逐渐缩小间隔直至为1。 - 代码示例: ```python def shell_sort(arr): n = len(arr) gap = n // 2 while gap > 0: for i in range(gap, n): temp = arr[i] j = i while j >= gap and arr[j-gap] > temp: arr[j] = arr[j-gap] j -= gap arr[j] = temp gap //= 2 return arr ``` 5. 归并排序(Merge Sort): - 基本原理:将待排序的序列递归地分成两半,对每半进行排序,然后将两个有序的半合并成一个有序序列。 - 代码示例: ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) return merge(left, right) def merge(left, right): result = [] i = j = 0 while i < len(left) and j < len(right): if left[i] < right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 result.extend(left[i:]) result.extend(right[j:]) return result ``` 6. 快速排序(Quick Sort): - 基本原理:选择一个基准元素,将小于基准的元素放在左边,大于基准的元素放在右边,然后递归地对左右两部分进行快速排序。 - 代码示例: ```python def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right) ``` 7. 堆排序(Heap Sort): - 基本原理:将待排序的序列建成一个大顶堆,然后依次取出堆顶元素并调整堆,直到堆为空。 - 代码示例: ```python def heap_sort(arr): n = len(arr) for i in range(n // 2 - 1, -1, -1): heapify(arr, n, i) for i in range(n-1, 0, -1): arr[i], arr[0] = arr[0], arr[i] heapify(arr, i, 0) return arr def heapify(arr, n, i): largest = i left = 2 * i + 1 right = 2 * i + 2 if left < n and arr[left] > arr[largest]: largest = left if right < n and arr[right] > arr[largest]: largest = right if largest != i: arr[i], arr[largest] = arr[largest], arr[i] heapify(arr, n, largest) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值