【数据结构】双向链表、二叉搜索树python实现

双向链表DoublyLinkedList

  • 双向链表和普通链表的不同之处是,双向链表可以通过尾部的tail访问到链表中的元素

  • 节点对象除了储存的el,还有perv 和next属性,指向链表的上一个元素和下一个元素

  • 对于添加元素时,对链表的head和tail重新赋值的代码需要放在最后,因为需要把之前的head和tail连接到新的元素

  • 操作时,需要考虑到当前节点的头和尾,上一节点的头和尾,下一节点的头和尾

class Node:
    def __init__(self,el):
        self.el = el
        self.prev = None
        self.next = None
class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None
        self.__lenth = 0
    def append(self,el):
        """
        尾部添加新的项"""
        new = Node(el)
        if self.__lenth == 0:
            self.head = new
            self.tail = new
        else:
            self.tail.next = new
            new.prev = self.tail
            self.tail = new
        self.__lenth += 1
    
    def insert(self,position,el):
        """
        指定位置插入新的项"""
        if position < 0 or position > self.__lenth:
            return '失败'
        new = Node(el)
        if position == 0:
            self.head.prev = new
            new.next = self.head
            self.head = new
        elif position == self.__lenth:
            self.tail.next = new
            new.prev = self.tail
            self.tail = new
        else:
            current = self.head.next
            for _ in range(position-1):
                current = current.next
            current.prev.next = new
            new.prev = current.prev
            new.next = current
            current.prev = new
        self.__lenth += 1

    def remove(self,el):
        """
        移除一项"""
        if self.head.el == el:
            self.head.next.prev = None
            self.head = self.head.next
            self.__lenth -= 1
            return True
        elif self.tail.el == el:
            self.tail.prev.next = None
            self.tail = self.tail.prev
            self.__lenth -= 1
            return True
        else:
            current = self.head.next
            for _ in range(self.__lenth-2):
                if el == current.el:
                    current.prev.next = current.next
                    current.next.prev = current.prev
                self.__lenth -= 1
                return True
            else:
                return False
    def indexOf(self,el):
        """
        返回元素所在链表的位置索引"""
        
        current = self.head
        for i in range(self.__lenth):
            if el == current.el:
                return i
            current = current.next
        else:
            return -1      
    def removeAt(self,position):
        """
        移除指定位置的一项"""
        if position>=self.__lenth or position < 0:
            return False
        if position == 0:
            self.head.next.prev = None
            self.head = self.head.next
            self.__lenth -= 1
            return True
        elif position == self.__lenth-1:
            self.tail.prev.next = None
            self.tail = self.tail.prev
            self.__lenth -= 1
            return True
        else:
            current = self.head
            for _ in range(position-1):
                current = current.next
            current.prev.next = current.next
            current.next.prev = current.prev
            self.__lenth -= 1                    
            return True
    def isEmpty(self):
        """
        判断链表是否为空"""
        return not bool(self.__lenth)
    
    def size(self):
        """
        返回链表的元素个数"""
        return self.__lenth
    
link = DoublyLinkedList()
# link.append(1)
# link.append(2)
# link.append(3)
# link.insert(0,0)
# link.insert(link.lenth,4)
# link.insert(1,1.5)
# print(link.size())
# link.remove(1.5)
# link.removeAt(1)
# print(link.indexOf(1.5))
# link.removeAt(3)
# print(link.head.el)
# print(link.head.next.el)
# print(link.head.next.next.el)
# print(link.head.next.next.next.el)
# print(link.tail.el)
# print(link.tail.prev.el)
# print(link.tail.prev.prev.el)
# print(link.tail.prev.prev.prev.el)
# print(link.isEmpty())

二叉搜素树Binary Search Tree

  • 节点中右左节点,右节点
  • 删除节点时需要判断要删除节点的情况,叶子节点,只有一个节点,有两个节点
    • 还需要区分删除根节点的情况
    • 如果有两个节点,需要找到节点的后继
    • 如果后继有子节点,且后继的父节点不是要删除的节点,需要把后继父节点的左节点指向后继的右节点
    • 遍历二叉树时,可以假设最简单的情况,或者可以把根节点的左右树看做两个节点,之后递归遍历左右树

class Node:
    def __init__(self,el):
        self.right = None
        self.left = None
        self.data = el

class BNT:
    def __init__(self):
        self.root = None
        
    def insert(self,key):
        # 插入新的节点
        node = Node(key)
        if self.root is None:
            self.root = node
        else:
            current = self.root
            parent = None
            while current:  # 直到当前节点为空
                parent = current
                if node.data > current.data:
                    current = current.right
                elif node.data < current.data:
                    current = current.left
            if node.data > parent.data:  # 当前节点的父节点有一个节点是空  判断之后插入
                parent.right = node
            elif node.data < parent.data:
                parent.left = node
                
    
    def search(self,key):
        # 搜索节点,如果存在,返回True
        if key == self.root.data:
            return True
        else:
            current = self.root
            while current:
                if key == current.data:
                    return True
                elif key > current.data:
                    current = current.right
                elif key < current.data:
                    current = current.left
            return False
    
    def prr(self,node):
        print(node.data)  # 传入一个节点就答应他的值
        if node.left is not None:  # 如果不是空,就继续传入函数
            self.prr(node.left)  # 先左 
        if node.right is not None:
            self.prr(node.right) # 后右
    def prrOrderTraverse(self):  
        # 先序
        self.prr(self.root)  # 从根节点开始
    def in_order(self,node):
        '''
        假设只有三个节点 
            11
        10       13
        print(node.data)
        if node.left is not None:
            print(node.left.data)  # 之后就把左子树 和 右子树 当作一个节点带入函数迭代
        if node.right is not None:
            print(node.right.data)
        '''
        # 中序
        if node.left is not None: # 如果不为空,就先传入函数
            self.in_order(node.left)
        print(node.data)  # 直到左节点为空,就打印
        if node.right is not None:  # 之后判断右节点 右树
            self.in_order(node.right)
            
    def inOrdefTraverse(self):
        # 中序
        self.in_order(self.root)
    
    def post(self,node):
        if node.left is not None:  # 先左树   左节点不为空就传入函数
            self.post(node.left)
        if node.right is not None:  #后右树   右节点不为空 也传入
            self.post(node.right)
        print(node.data) # 左右节点都为空才打印 
    def postOrderTraverse(self):
        # 后序
        self.post(self.root)
    def min(self):
        # 最小
        current = self.root
        while current.left:
            current = current.left
        return current.data
    
    def max(self):
        # 最大
        current = self.root
        while current.right:
            current = current.right
        return current.data
    
    def remove(self,key):
        # 移除
        def houji(node):
            prev = None
            node = node.right  # 从右树中找
            while node.left:
                prev = node
                node = node.left
            return node,prev
        if not self.search(key):
            return False
        else:
            if key == self.root.data: # 如果删除的是根节点
                if self.root.left is None and self.root.right is None:  # 如果根节点没有子节点
                    self.root = None
                elif self.root.left is None:
                    self.root = self.root.right
                elif self.root.right is None:
                    self.root = self.root.left
                else:
                    hou_ji,prev = houji(self.root)
                    if self.root != prev: # 删除的节点不是后继的父节点 
                        prev.left = hou_ji.right  # 后继的父节点指向后继的右节点
                    hou_ji.right = self.root.right
                    hou_ji.left = self.root.left
                    self.root = hou_ji
            else:
                current = self.root # 要删除的节点
                parent = None # 父节点
                is_left =True
                while key != current.data:
                    if key>current.data:
                        if current.right is not None:
                            parent = current
                            current = current.right
                            is_left = False
                        else:
                            return False
                    elif key<current.data:
                        if current.left is not None:
                            parent = current
                            current = current.left
                        else:
                            return False
                # 如果要删除的节点没有子节点
                if current.left is None and current.right is None:# 都为空 返回false
                    if is_left:# 如果为父节点的左节点
                        parent.left = None
                    else: 
                        parent.right = None
                elif current.left is None and current.right is not None:# 只有右节点
                    if is_left:# 如果为父节点的左节点
                        parent.left = current.right
                    else: 
                        parent.right = current.right
                elif current.left is not None and current.right is None:
                    if is_left:# 如果为父节点的左节点
                        parent.left = current.left
                    else: 
                        parent.right = current.left
                elif current.left is not None and current.right is not None: # 有两个节点
                    hou_ji,prev = houji(current) # 找到后继和后继的父节点
                    if prev != current: # 如果后继的父节点不是要删除的节点
                        prev.left = hou_ji.right
                    hou_ji.left = current.left
                    hou_ji.right = current.right
                    # hou_ji.right = current.right
                    if is_left:# 如果为父节点的左节点
                        parent.left = hou_ji
                    else: 
                        parent.right = hou_ji
                    
                    
            return True

tree = BNT()
tree.insert(11)
# tree.insert(7)
# tree.insert(15)
# tree.insert(5)
# tree.insert(3)
# tree.insert(9)
# tree.insert(8)
# tree.insert(10)
# tree.insert(13)
# tree.insert(12)
# tree.insert(14)
# tree.insert(20)
# tree.insert(18)
# tree.insert(25)
tree.remove(11)
# tree.remove(15)
# tree.remove(20)
tree.prrOrderTraverse()
# tree.inOrdefTraverse()
# tree.postOrderTraverse()
# print(tree.min())
# print(tree.max())
# print(tree.root.data)
# print(tree.root.left.data)
# print(tree.root.left.left.data)
# print(tree.root.left.left.left.data)
# print(tree.root.data)
# print(tree.root.right.data)
# print(tree.root.right.right.data)
# print(tree.root.right.right.right.data)
# print(tree.search(4))
# print(tree.search(26))
# print(tree.search(8))
# print(tree.search(11.5))
  • 15
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值