zoukankan      html  css  js  c++  java
  • 数据结构


    • 数据结构是指相互之间存在着一种或多种关系的数据元素的结合和该集合中数据元素之间的关系组成。

    • 简单来说,数据结构就是设计数据 以何种方式组织并存储在计算机中

    • 例如:列表、集合与字典等都是一种数据结构。

    • N.Wirth:"程序=数据结构+算法"

    数据结构的分类

    数据机构按照其逻辑结构可分为线性结构、树结构、图结构

    1. 线性结构:数据结构中的元素存在一对一的相互关系
    2. 树结构:数据结构中的元素存在一对多的相互关系
    3. 图结构:数据结构中的元素存在多对多的相互关系

    1、列表/数组

    列表(其它语言是数组)是一种基本数据类型。

    关于列表问题:

      1、列表的元素是如何存储的?(存内存地址(64位机器固定8bytes))

      2、如何查找元素?(从列表起始位置的内存地址,查第几个元素就起始位置加n*8)

      3、列表不用显示声明长度?(python内部通过完整拷贝来调整列表长度)

    2、栈

    栈(Stack)是一个数据集合,可以理解为只能在一端进行插入或删除操作的列表。

    栈的特点:后进先出 LIFO

    栈的概念:栈顶,栈底

    栈的基本操作:

    • 进栈(压栈):push
    • 出栈:pop
    • 取栈顶:gettop

    栈的实现

     使用一般的列表即可实现栈

    • 进栈:li.append
    • 出栈:li.pop
    • 取栈顶:li[-1]
    class Stack:
    
        def __init__(self):
            self.stack = []
    
        def push(self, data):
            self.stack.append(data)
    
        def pop(self):
            return self.stack.pop()
    
        def get_top(self):
            if len(self.stack) > 0:
                return self.stack[-1]
            else:
                return None
    
        def is_empty(self):
            return len(self.stack) > 0

    栈的应用 -- 括号匹配问题

     括号匹配问题:给一个字符串,其中包括小括号、中括号、大括号,求该字符串中的括号是否匹配。

    例如:

      • ()()[]{}  匹配
      • ([{()}])  匹配
      • [](             不匹配
      • ([)]            不匹配
    def brace_match(s):
        match = {'}': '{', ']': '[', ')': '('}
        stack = Stack()
        for ch in s:
            if ch in {'(', '[', '{'}:
                stack.push(ch)
            else:   # ch in {'}',']',')'}
                if stack.is_empty():
                    return False
                elif stack.get_top() == match[ch]:
                    stack.pop()
                else:
                    return False
    
        if stack.is_empty():
            return True
        else:
            return False
    
    
    print(brace_match('[{()}(){()}[]({}){}]'))
    print(brace_match('[]}'))
    View Code

    3、队列

    队列(queue)是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除。

    • 进行插入的一点称为队尾(rear),插入动作成为进队或入队。
    • 进行删除的的一端称为对头(front),删除动作称为出队。
    • 队列的性质:先进先出(First-in, First-out)

    队列的实现

    初步设想:列表+两个下标指针

    创建一个列表和两个变量,front变量指向队首,rear变量指向队尾。初始时,front和rear都为0

    进队操作:元素写到li[rear]的位置,rear自增1

    出队操作:返回li[front]的元素,front自增1

    出现d的情况后,队列无法继续添加元素,但是列表里面有位置是空的,这一点非常不好

    队列的实现原理 -- 环形队列

    环形队列:当队尾指针front == Maxsize + 1时,再前进一个位置就自动到0

     实现方式:求余运算

    队首指针前进1:front = (front+1) % maxsize

    队尾指针前进1:rear = (rear+1) % maxsize

    队空条件:rear == front队满条件:(rear+1)% maxsize == front

    class Queue:
        def __init__(self, size=100):
            self.queue = [0 for i in range(size)]
            self.size = size
            self.rear = 0   # 队尾指针
            self.front = 0  # 队首指针
    
        def push(self, element):
            if not self.is_filled():
                self.rear = (self.rear + 1) % self.size
                self.queue[self.rear] = element
            else:
                raise IndexError("Queue is filled.")
    
        def pop(self):
            if not self.is_empty():
                self.front = (self.front + 1) % self.size
                return self.queue[self.front]
            else:
                raise IndexError("Queue is empty.")
    
        # 判断队空
        def is_empty(self):
            return self.rear == self.front
    
        # 判断队满
        def is_filled(self):
            return (self.rear + 1) % self.size == self.front
    
    
    q = Queue(5)
    for i in range(4):
        q.push(i)
    print(q.pop())
    q.push(4)
    View Code

    队列的内置模块

    使用方法:from collections import deque

    创建队列:queue = deque(li)

    进队:append

    出队:popleft

    双向队列队首进队:appendleft

    双向队列队尾进队:pop

    栈和队列的应用 -- 迷宫问题

    解决方法1:栈--深度优先搜索(回溯法)

    思路:从一个节点开始,任意找下一个能走的点,当找不到能走的点时,退回上一个点寻找是否有其他方向的点。
    (使用栈存储当前路径)
    maze = [
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
        [1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
        [1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
        [1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
        [1, 0, 1, 0, 0, 0, 1, 0, 0, 1],
        [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
        [1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    ]
    
    dirs = [
        lambda x, y: (x+1, y),
        lambda x, y: (x, y+1),
        lambda x, y: (x-1, y),
        lambda x, y: (x, y-1)
    ]
    
    
    def maze_path(x1, y1, x2, y2):
        stack = []
        stack.append((x1, y1))
        while len(stack) > 0:
            curNode = stack[-1]     # 当前节点
            if curNode[0] == x2 and curNode[1] == y2:
                # 走到终点了
                for p in stack:
                    print(p)
                return True
    
            # x,y 四个方向  x+1, y; x, y+1; x-1, y; x, y-1
            for dir in dirs:
                next_Node = dir(curNode[0], curNode[1])
                # 如果下一个节点能走
                if maze[next_Node[0]][next_Node[1]] == 0:
                    stack.append(next_Node)
                    maze[next_Node[0]][next_Node[1]] = 2
                    break
            else:   # 一个都找不到
                maze[next_Node[0]][next_Node[1]] = 2
                stack.pop()
        else:
            print('没有路')
            return False
    
    maze_path(1,1,8,8)
    View Code

    4、链表

    链表是由一系列节点组成的元素集合。每个元素包含两部分,数据域item和指向下一个节点的指针next。通过节点之间的相互连接,最终串联称一个链表。

     创建链表

    class Node:
        def __init__(self, data):
            self.data = data
            self.next = None
    
    
    # 头插法
    def create_linklist(li):
        head = Node(li[0])
        for num in li[1:]:
            node = Node(num)
            node.next = head
            head = node
        return head
    
    # 尾插法
    def create_taillist(li):
        head = Node(li[0])
        tail = head
        
        for num in li:
            node = Node(num)
            tail.next = node
            tail = node
        return head
    
    # 链表的遍历
    def print_link(lk):
        while lk:
            print(lk.data, end=',')
            lk = lk.next
    View Code

    链表节点的插入和删除

    插入:

    p.next = curNode.next
    curNode.next = p

    删除:

     curNode.next=p.next

     del p

    双链表

    双链表的每个节点有两个指针:一个指向后一个节点,另一个指向前一个节点(单链表只有next)

    双链表的插入和删除

    插入:

      p.next = curNode.next

      curNode.next.prior = p

      p.prior = curNode

      curNode.next = p

    删除:

      curNode.next = p.next

      p.next.prior = curNode

      del p

    链表与顺序表

    • 链表在插入和删除的操作上明显快于顺序表
    • 链表的内存可以更灵活的分配

    5、哈希表

    哈希表是一个通过哈希函数来计算数据存储位置的数据结构,通常支持如下操作:

    1. insert(key, value):插入键值对(key,value)
    2. get(key):如果存在键值对则返回其value,否则返回空值
    3. delete(key):删除键为key的键值对

    知识储备-- 直接寻址表

    当关键字的全域U比较小时,直接寻址表是一种简单而有效的方法

    直接寻址技术缺点:

    • 当域U很大时,需要消耗大量内存,很不实际
    • 如果域很大而实际出现的key很小,则大量空间被浪费
    • 无法处理关键字不是数字的情况

    改进直接寻址表:哈希

    • 构建大小为m的寻址表T
    • key为k的元素放到h(k)的位置上
    • h(k)是一个函数,其将域U映射到表T[0, 1, ..., m-1]

    哈希表(又称为散列表),是一种线性表的存储结构。哈希表由一个直接寻址表和一个哈希函数组成。哈希函数h(k)将元素关键字k作为自变量,返回元素的存储下标。

    假设有一个长度为7的哈希表,哈希函数h(k)=k%7    元素集合{14, 22, 3, 5}的存储方式如下图:

    哈希冲突

    由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因为对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况,这种情况叫做哈希冲突!

    比如h(k)=k%7, h(0)=h(7)=h(14)...

    解决哈希冲突的两个办法:

    1、开放寻执法:如果哈希函数返回的位置已经有值,则可以向后探查新的位置来存储这个值。

    • 线性探查:如果位置i被占用,则探查i+1,i+2,...
    • 二次探查:如果位置i被占用,则探查则探查i+12,i-12,i+22,i-22,……(2表示平方)
    • 二度哈希:有n个哈希函数,当使用第一个哈希函数h1发生冲突时,则尝试使用h2,h3,...

    2、拉链法:哈希表每个位置都连接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后

    拉链法解决hash冲突代码实现:

    # 链表类
    class LinkList:
        class Node:
            def __init__(self, item=None):
                self.item = item
                self.next = None
    
        class LinkListIterator:
            def __init__(self, node):
                self.node = node
    
            def __next__(self):
                if self.node:
                    cur_node = self.node
                    self.node = cur_node.next
                    return cur_node.item
                else:
                    raise StopIteration
    
            def __iter__(self):
                return self
    
        def __init__(self, iterable=None):
            self.head = None
            self.tail = None
            if iterable:
                self.extend(iterable)
    
        def append(self, obj):
            s = LinkList.Node(obj)
            if not self.head:
                self.head = s
                self.tail = s
            else:
                self.tail.next = s
                self.tail = s
    
        def extend(self, iterable):
            for obj in iterable:
                self.append(obj)
    
        def find(self, obj):
            for n in self:
                if n == obj:
                    return True
            else:
                return False
    
        def __iter__(self):
            return self.LinkListIterator(self.head)
    
        def __repr__(self):
            return "<<"+", ".join(map(str, self))+">>"
    
    
    # 类似于集合的结构
    class HashTable:
        def __init__(self, size=101):
            self.size = size
            self.T = [LinkList() for i in range(self.size)]
    
        def h(self, k):
            return k % self.size
    
        def insert(self, k):
            i = self.h(k)
            if self.find(k):
                print("Duplicated Insert")
            else:
                self.T[i].append(k)
    
        def find(self, k):
            i = self.h(k)
            return self.T[i].find(k)
    
    
    ht = HashTable()
    
    ht.insert(0)
    ht.insert(1)
    ht.insert(3)
    ht.insert(102)
    ht.insert(508)
    
    print(",".join(map(str, ht.T)))
    print(ht.find(203))
    View Code

    哈希表 -- 常见哈希函数

    除法哈希法:  h(k) = k % m

    乘法哈希法:  h(k) = floor(m*(A*Key%1))

    全域哈希法:  ha,b(k) = ((a*key + b) mod p) mod m a,b=1,2,...,p-1

    哈希表的应用 -- 集合与字典

    字典与集合都是通过哈希表来实现的。

    a = {'name':xcq, 'age':18, 'gender':'Man'}

    使用哈希表存储字典,通过哈希函数将字典的键映射为下标。假设h('name')=3, h('age'=1),h('gender'=4), 则哈希表存储为[Node, 18, Node, 'xcq', 'Man']

    如果发生哈希冲突,则通过拉链法或则开放寻址法解决。

    6、二叉树

    树是一种数据结构 比如:目录结构

    树是一种可以递归定义的数据结构  树是由n个节点组成的集合

      如果n=0, 那这是一颗空树

      如果n>0, 那存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树

    二叉树:度不超过2的树(节点最多有两个叉)

    二叉树的链式存储:

    将二叉树的节点定义为一个对象,节点之间通过类似链表的连接方式来连接

    二叉树的4种遍历方式:

    1. 前序遍历:EACBDGF
    2. 中序遍历:ABCDEGF
    3. 后序遍历:BDCAFGE
    4. 层次遍历:EAGCFBD
    class BiTreeNode:
        def __init__(self, data):
            self.data = data
            self.lchild = None
            self.rchild = None
    
    a = BiTreeNode("A")
    b = BiTreeNode("B")
    c = BiTreeNode("C")
    d = BiTreeNode("D")
    e = BiTreeNode("E")
    f = BiTreeNode("F")
    g = BiTreeNode("G")
    
    e.lchild = a
    e.rchild = g
    a.rchild = c
    c.lchild = b
    c.rchild = d
    g.rchild = f
    
    root = e
    # 前序遍历
    def pre_order(root):
        if root:
            print(root.data, end=',')
            pre_order(root.lchild)
            pre_order(root.rchild)
    
    # 中序遍历
    def in_order(root):
        if root:
            in_order(root.lchild)
            print(root.data, end=',')
            in_order(root.rchild)
    
    # 后序遍历
    def post_order(root):
        if root:
            post_order(root.lchild)
            post_order(root.rchild)
            print(root.data, end=',')
    
    # 层级遍历
    from collections import deque
    def level_order(root):
        que = deque()
        que.append(root)
        while len(que):
            node = que.popleft()
            print(node.data, end=',')
            if node.lchild:
                que.append(node.lchild)
            if node.rchild:
                que.append(node.rchild)
    二叉树的4种遍历方式

    二叉搜索树

    二叉搜索树是一棵二叉树且满足性质:设x是二叉树的一个节点。如果y是x的左子树的一个节点,那么y.key <= x.key;如果y是x的右子树的一个节点,那么y.key >= x.key

    (左边的都比根节点小,右边的都比根节点大)

    二叉搜索树的操作:查询、插入、删除

    需要注意的是删除操作

    删除操作分3种情况:

    1、如果要删除的节点是叶子节点:直接删除

    2、如果要删除的节点只有一个孩子:将此节点的父亲与孩子连接,然后删除该节点

    3、如果要删除的节点有两个孩子:将其右子树最小节点删除,并替换当前节点。

    二叉搜索树查询、插入、删除代码实现

    import random
    
    class BiTreeNode:
        def __init__(self, data):
            self.data = data
            self.lchild = None   # 左孩子
            self.rchild = None  # 右孩子
            self.parent = None
    
    class BST:
        def __init__(self, li=None):
            self.root = None
            if li:
                for val in li:
                    self.insert_no_rec(val)
    
        # 插入(递归)
        def insert(self, node, val):
            if not node:
                node = BiTreeNode(val)
            elif val < node.data:
                node.lchild = self.insert(node.lchild, val)
                node.lchild.parent = node
            elif val > node.data:
                node.rchild = self.insert(node.rchild, val)
                node.rchild.parent = node
            return node
    
        # 插入(非递归)
        def insert_no_rec(self, val):
            p = self.root
            if not p:               # 空树
                self.root = BiTreeNode(val)
                return
            while True:
                if val < p.data:
                    if p.lchild:
                        p = p.lchild
                    else:           # 左孩子不存在
                        p.lchild = BiTreeNode(val)
                        p.lchild.parent = p
                        return
                elif val > p.data:
                    if p.rchild:
                        p = p.rchild
                    else:
                        p.rchild = BiTreeNode(val)
                        p.rchild.parent = p
                        return
                else:
                    return
    
        # 查询(递归)
        def query(self, node, val):
            if not node:
                return None
            if node.data < val:
                return self.query(node.rchild, val)
            elif node.data > val:
                return self.query(node.lchild, val)
            else:
                return node
    
        # 查询(非递归)
        def query_no_rec(self, val):
            p = self.root
            while p:
                if p.data < val:
                    p = p.rchild
                elif p.data > val:
                    p = p.lchild
                else:
                    return p
            return None
    
        def pre_order(self, root):
            if root:
                print(root.data, end=',')
                self.pre_order(root.lchild)
                self.pre_order(root.rchild)
    
        def in_order(self, root):
            if root:
                self.in_order(root.lchild)
                print(root.data, end=',')
                self.in_order(root.rchild)
    
        def post_order(self, root):
            if root:
                self.post_order(root.lchild)
                self.post_order(root.rchild)
                print(root.data, end=',')
    
    
        def __remove_node_1(self, node):
            # 情况1:node是叶子节点
            if not node.parent:
                self.root = None
            if node == node.parent.lchild:  #node是它父亲的左孩子
                node.parent.lchild = None
            else:   #右孩子
                node.parent.rchild = None
    
        def __remove_node_21(self, node):
            # 情况2.1:node只有一个左孩子
            if not node.parent: # 根节点
                self.root = node.lchild
                node.lchild.parent = None
            elif node == node.parent.lchild:
                node.parent.lchild = node.lchild
                node.lchild.parent = node.parent
            else:
                node.parent.rchild = node.lchild
                node.lchild.parent = node.parent
    
        def __remove_node_22(self, node):
            # 情况2.2:node只有一个右孩子
            if not node.parent:
                self.root = node.rchild
            elif node == node.parent.lchild:
                node.parent.lchild = node.rchild
                node.rchild.parent = node.parent
            else:
                node.parent.rchild = node.rchild
                node.rchild.parent = node.parent
    
    
        def delete(self, val):
            if self.root:   # 不是空树
                node = self.query_no_rec(val)
                if not node: # 不存在
                    return False
                if not node.lchild and not node.rchild: #1. 叶子节点
                    self.__remove_node_1(node)
                elif not node.rchild:       # 2.1 只有一个左孩子
                    self.__remove_node_21(node)
                elif not node.lchild:       # 2.2 只有一个右孩子
                    self.__remove_node_22(node)
                else:   # 3. 两个孩子都有
                    min_node = node.rchild
                    while min_node.lchild:
                        min_node = min_node.lchild
                    node.data = min_node.data
                    # 删除min_node
                    if min_node.rchild:
                        self.__remove_node_22(min_node)
                    else:
                        self.__remove_node_1(min_node)
    
    
    
    
    #
    #
    # tree = BST([1,4,2,5,3,8,6,9,7])
    # tree.in_order(tree.root)
    # print("")
    #
    # tree.delete(4)
    # tree.delete(1)
    # tree.delete(8)
    # tree.in_order(tree.root)
    View Code

    二叉搜索树的效率

    平均情况下,二叉搜索树进行搜索的时间复杂度为O(nlogn)

    最坏情况下,二叉搜索树可能非常偏斜(线性)

    解决方案:

    • 随机化插入
    • AVL树

    7、AVL树

    AVL树是一颗自平衡的二叉搜索树。

    AVL树具有一下性质:

    • 根的左右子树的高度差的绝对值不能超过1
    • 根的左右子树都是平衡二叉树

    AVL树--插入

    插入一个节点可能会破坏AVL树的平衡,可以通过旋转操作来进行修正。

    插入一个节点后,只有从插入节点到根节点的路径上的节点的平衡可能被改变。我们需要找出第一个破坏了平衡条件的节点,称之为K。k的左右子树高度差的绝对值为2

    不平衡的出现可能会有4种情况

    1、左旋

    不平衡是由于对k的右孩子的右子树插入导致的

    2、右旋

    不平衡是由于对k的左孩子的左子树插入导致的

    3、右旋-左旋

    不平衡是由于对K的右孩子的左子树插入导致的

    4、左旋-右旋

    AVL树插入操作代码实现:

    from bst import BiTreeNode, BST
    
    class AVLNode(BiTreeNode):
        def __init__(self, data):
            BiTreeNode.__init__(self, data)
            self.bf = 0
    
    class AVLTree(BST):
        def __init__(self, li=None):
            BST.__init__(self, li)
    
        def rotate_left(self, p, c):
            s2 = c.lchild
            p.rchild = s2
            if s2:
                s2.parent = p
    
            c.lchild = p
            p.parent = c
    
            p.bf = 0
            c.bf = 0
            return c
    
        def rotate_right(self, p, c):
            s2 = c.rchild
            p.lchild = s2
            if s2:
                s2.parent = p
    
            c.rchild = p
            p.parent = c
    
            p.bf = 0
            c.bf = 0
            return c
    
        def rotate_right_left(self, p, c):
            g = c.lchild
    
            s3 = g.rchild
            c.lchild = s3
            if s3:
                s3.parent = c
            g.rchild = c
            c.parent = g
    
            s2 = g.lchild
            p.rchild = s2
            if s2:
                s2.parent = p
            g.lchild = p
            p.parent = g
    
            # 更新bf
            if g.bf > 0:
                p.bf = -1
                c.bf = 0
            elif g.bf < 0:
                p.bf = 0
                c.bf = 1
            else: # 插入的是g
                p.bf = 0
                c.bf = 0
            return g
    
        def rotate_left_right(self, p, c):
            g = c.rchild
    
            s2 = g.lchild
            c.rchild = s2
            if s2:
                s2.parent = c
            g.lchild = c
            c.parent = g
    
            s3 = g.rchild
            p.lchild = s3
            if s3:
                s3.parent = p
            g.rchild = p
            p.parent = g
    
            # 更新bf
            if g.bf < 0:
                p.bf = 1
                c.bf = 0
            elif g.bf > 0:
                p.bf = 0
                c.bf = -1
            else:
                p.bf = 0
                c.bf = 0
            return g
    
        def insert_no_rec(self, val):
            # 1、和BST一样插入(AVL要一边插入一边控制balance factor)
            p = self.root
            if not p:  # 空树
                self.root = AVLNode(val)
                return
            while True:
                if val < p.data:
                    if p.lchild:
                        p = p.lchild
                    else:  # 左孩子不存在
                        p.lchild = AVLNode(val)
                        p.lchild.parent = p
                        node = p.lchild  # node 存储的就是插入的节点
                        break
                elif val > p.data:
                    if p.rchild:
                        p = p.rchild
                    else:
                        p.rchild = AVLNode(val)
                        p.rchild.parent = p
                        node = p.rchild
                        break
                else:  # val == p.data
                    return
    
            # 2、更新balance factor
            while node.parent:      # node.parent 不空
                if node.parent.lchild == node:      # 传递是从左子树来的, 左子树更沉了
                    # 更新node.parent的bf -= 1
                    if node.parent.bf < 0:      # 原来node.parent.bf = -1, 更新后变成-2
                        # 做旋转
                        # 看node那边沉
                        g = node.parent.parent  # 为了链接旋转后的子树
                        x = node.parent
                        if node.bf > 0:
                            n = self.rotate_left_right(node.parent, node)
                        else:
                            n = self.rotate_right(node.parent, node)
                        # 记得:把n和g连起来
                    elif node.parent.bf > 0:    # 原来node.parent.bf = 1更新后等于0
                        node.parent.bf = 0
                        break
                    else:   # 原来node.parent.bf = 0, 更新之后变成-1
                        node.parent.bf = -1
                        node = node.parent
                        continue
    
                else:   # 传递是从右子树来的,右子树更沉了
                    # 更新node.parent.bf += 1
                    if node.parent.bf > 0:  # 原来node.parent.bf =1< 更新后变成2
                        # 做旋转
                        # 看node哪边沉
                        g = node.parent.parent  # 为了连接旋转之后的子树
                        x = node.parent     # 旋转前的子树的根
                        if node.bf < 0:     # node.bf = -1
                            n = self.rotate_right_left(node.parent, node)
                        else:
                            n = self.rotate_left(node.parent, node)
                        # 记得连起来
                    elif node.parent.bf < 0:    # 原来node.parent.bf = -1, 更新之后变成0
                        node.parent.bf = 0
                        break
                    else:   # 原来node.parent.bf = 0, 更新之后变成1
                        node.parent.bf = 1
                        node = node.parent
                        continue
    
                # 连接旋转后的子树:
                n.parent = g
                if g:   # g不是空
                    if x == g.lchild:
                        g.lchild = n
                    else:
                        g.rchild = n
                    break
                else:
                    self.root = n
                    break
    AVL树插入操作
  • 相关阅读:
    LLDB 常用的调试命令
    iOS https认证
    pod lib lint xxx.podspec 验证出错 Could not find a `ios` simulator
    LLDB 调试
    First throw call stack: 不打印方法名
    AOP
    增强现实
    2017
    iOS的主要框架介绍 (转载)
    iOS中都有什么设计模式?各个设计模式的作用 (转载)
  • 原文地址:https://www.cnblogs.com/Xuuuuuu/p/10846124.html
Copyright © 2011-2022 走看看