python数据结构学习笔记

第一部分 小顶堆

#异常类
class BinHeapError(ValueError): 
    pass

#初始化堆
class BinHeap:
    '''采用list储存数据:(若某节点的下标为i)
            1.其左子节点的下标为2*i
            2.其右子节点的下标为2*i+1
            3.其父节点的下标为i//2  '''
    def __init__(self, elist):
        # 保证下标从1开始
        self.data = [0] + elist  # [0]无用的数据
        '''调用自身的buildHeap函数将elist转换为堆'''
        if elist is not None:
            self.buildHeap(self.data)

    # 判断堆是否为空,返回布尔值
    def is_Empty(self):
        return self.data == [0]

    # 查看堆顶的值
    def peek(self):
        if self.is_Empty():
            raise BinHeapError("in peek")
        return self.data[1]

	#入堆
    def enqueue(self, elem):
        """将elem加入到连续表尾部,然后调用siftup进行一次向上筛选"""
        self.data.append(elem)
        self.siftup(elem, len(self.data)-1)

    #向上筛选
    def siftup(self, elem, last):
        """将加入的节点与父节点做比较,如果父节点大于加入的节点,交换两者的数据"""
        i, j = last, last//2
        #i:当前节点下标  j:当前节点父节点下标
        while i > 0 and elem < self.data[j]:
            self.data[i],self.data[j] = self.data[j],self.data[i]
            '''更新当前节点的下标和当前节点的父节点下标,准备进入第下次循环'''
            i, j = j, j//2
	
	#出堆
    def dequeue(self):
        if self.is_Empty():
            raise BinHeapError("in dequeue")
        """ 用pop()将尾部数据放置到堆顶,然后调用siftdown进行一次向下筛选
            e0:要移除的数据 e:放置在堆顶的数据 """
        e0, e = self.data[1], self.data.pop()
        self.siftdown(e, 1, len(self.data)-1)
        return e0

    #向下筛选
    def siftdown(self, e, begin, end):
        """ 通过向下筛选找到e应该所在位置的下标i
            i:当前节点下标 j:当前节点的父节点下标
            newList与self.data指向同一个列表 """
        newList, i , j = self.data, begin, begin*2
        while j <= end: #要带等号
            """比较当前节点的左右子节点大小,获得最小的子节点下标"""
            if j+1 <= end and newList[j+1] < newList[j]: #要带等号
                j += 1
            if e < newList[j]:
                #找到插入位置i
                break
            newList[i] = newList[j]
            '''更新当前节点的下标和当前节点的父节点下标,准备进入第下次循环'''
            i, j = j, 2*j
        newList[i] = e
	
	#调整为堆
    def buildHeap(self, list):
        """ 从下标为end//2开始,通过向下筛选一个个建堆,时间复杂度nlogn"""
        end = len(list) - 1
        for i in range(end//2, 0, -1):
            self.siftdown(list[i], i, end)

#测试
if __name__ == '__main__':
    import random
    list=[]
    for k in range(10):
        list.append(random.randint(0,100))
    print(list)
    Bt = BinHeap(list)
    print(Bt.data, Bt.is_Empty())
    Bt.enqueue(10)
    print(Bt.data)

第二部分 二叉排序树

在接下来的前根序遍历中采用栈来缓存

from Stack_List import SStack

每一个节点的类(属性)

class TreeNode: 
    #初始化节点类
    def __init__(self, key, val, left=None, right=None, parent=None):
        self.key = key
        self.payload = val
        self.leftChild = left
        self.rightChild = right
        self.parent = parent

    #判断当前节点的连接情况
    def hasLeftChild(self):
        return self.leftChild
    def hasRightChild(self):
        return self.rightChild
    def isLeftChild(self):
        return self.parent and self.parent.leftChild==self
    def isRightChild(self):
        return self.parent and self.parent.rightChild==self

    #判断当前节点的位置
    def isRoot(self):
        return not self.parent
    def isLeaf(self):
        return not(self.leftChild or self.rightChild)
    def hasAnyChildren(self): #只有一棵子树
        return self.leftChild or self.rightChild
    def hasBothChildren(self): #有两棵子树
        return self.rightChild and self.leftChild

    # 更改当前节点的数据
    def replaceNodeData(self, key, value, lc, rc):
        self.key = key
        self.payload = value
        self.leftChild = lc
        self.rightChild = rc
        if self.hasLeftChild(): #为左子节点增加父节点指向
            self.leftChild.parent = self
        if self.hasRightChild(): #为右子节点增加父节点指向
            self.rightChild.parent = self

    #前根序遍历
    def _Traversal(self, t):
        '''能力有限,暂时不会用栈实现中根序遍历'''
        st = SStack()
        while t is not None or not st.is_Empty():
            while t is not None:  #沿左支下行
                print(t.payload)
                st.push(t.rightChild) #右分支入栈
                t = t.leftChild
            t = st.pop()  #回溯

实现二叉排序树

class BinarySearchTree:
    # 初始化二叉排序树
    def __init__(self):
        self.root = None
        self.size = 0

    #辅助函数
    def length(self):
        return self.size
    def __len__(self):
        return self.size
    def Traversal(self):
        return self.root._Traversal(self.root)

增加数据

	def put(self, key, val):
        '''有根节点:  调用_put函数
           没有根节点:设为根节点'''
        if self.root:
            self._put(key, val, self.root)
        else:
            self.root = TreeNode(key, val)
        self.size += 1 #节点个数加1

    def _put(self, key, val, currentNode):
        '''key小于当前节点的key:
                当前节点有左子树:  递归调用_put(递归左子树)
                当前节点没有左子树:设为当前节点的左子节点
           key大于当前节点的key:
                当前节点有右子树:  递归调用_put(递归右子树)
                当前节点没有右子树:设为当前节点的右子节点'''
        if currentNode.key > key:
            if currentNode.hasLeftChild():
                self._put(key, val, currentNode.leftChild)
            else:
                currentNode.leftChild=TreeNode(key, val, parent=currentNode)
        else:
            if currentNode.hasRightChild():
                self._put(key, val, currentNode.rightChild)
            else:
                currentNode.rightChild=TreeNode(key, val, parent=currentNode)

    def __setitem__(self, key, value): #索引赋值
        '''调用自身的put函数'''
        self.put(key, value)

查找数据

    def get(self, key):
        '''有根节点:  调用_get,找到key对应的res
                        1.找到了res: 返回res的值
                        2.没有找到res:返回None
           没有根节点:返回None'''
        if self.root:
            res = self._get(key, self.root)
            if res:
                return res.payload
            else:
                return None
        else:
            return None

    def _get(self, key, currentNode):
        '''currentNode是空:    返回None
           key等于当前节点的key:返回当前节点
           key小于当前节点的key:递归调用_get(递归左子树)
           key大于当前节点的key:递归调用_get(递归右子树)'''
        if not currentNode:
            return None
        elif key == currentNode.key:
            return currentNode
        elif key < currentNode.key:
            return self._get(key, currentNode.leftChild)
        else:
            return self._get(key, currentNode.rightChild)

    def __getitem__(self, key): #索引
        '''调用自身的get函数'''
        return self.get(key)
    def __contains__(self, key): #相当与in函数
        if self._get(key, self.root):
            '''调用自身的_get函数'''
            return True
        else:
            return False

删除数据

    def delete(self, key):
        '''有两个及以上的节点:调用_get找到要删除的节点
                     1.找到了nodeToRemove:    调用remove函数删除
                     2.没有找到了nodeToRemove:报错
           一个结点(只有根节点):
                    1.根节点的key等于key:根节点设为None
                    2.根节点的key不等于key:报错
           没有节点:报错'''
        if self.size > 1:
            nodeToRemove = self._get(key, self.root)
            if nodeToRemove:
                self.remove(nodeToRemove)
                self.size = self.size - 1 #节点个数减1
            else:
                raise KeyError("Error,key not in tree")
        elif self.size==1 and self.root.key==key:
            self.root = None
            self.size = self.size-1 #节点个数减1
        else:
            raise KeyError("Error,key not in tree")

    def __delitem__(self, key):
        '''调用自身的delete函数'''
        self.delete(key)

    def remove(self, currentNode):
        '''1.当前节点是叶节点
           2.当前节点有两棵子树
           3.当前节点只有一棵子树'''
        if currentNode.isLeaf():
            '''当前节点是叶节点:
                    1.当前节点是左子节点:将当前节点的父节点的左树设为None
                    2.当前节点是右子节点:将当前节点的父节点的有树设为None'''
            if currentNode==currentNode.parent.leftChild:
                currentNode.parent.leftChild = None
            else:
                currentNode.parent.rightChild = None
        elif currentNode.hasBothChildren():
            '''当前节点有两棵子树:
                    1.调用findSuccessor函数找到当前节点右子树上key最小的节点succ
                    2.调用spliceOut函数摘除succ
                    3.将succ替代掉当前节点'''
            succ = self.findSuccessor(currentNode)
            self.spliceOut(succ)
            currentNode.key = succ.key
            currentNode.payload = succ.payload
        else:
            '''当前节点只有一棵子树:
                        1.当前节点没有父节点:       
                                1.将根节点指向当前节点的左子节点
                左子树:  2.当前节点是父节点的左子节点:
                                1.当前节点的左子节点的父节点指向当前节点的父节点
                                2.当前节点的父节点的左子树指向当前节点的左子节点
                        3.当前节点是父节点的右子节点:
                                1.当前节点的左子节点的父节点指向当前节点的父节点
                                2.当前节点的父节点的右子树指向当前节点的左子节点'''
            if currentNode.hasLeftChild():
                if currentNode.isRoot():
                    self.root = currentNode.leftChild
                elif currentNode.isLeftChild():
                    currentNode.leftChild.parent = currentNode.parent
                    currentNode.parent.leftChild = currentNode.leftChild
                else:
                    currentNode.leftChild.parent = currentNode.parent
                    currentNode.parent.rightChild = currentNode.leftChild
            else:
                '''1.当前节点没有父节点:
                        1.将根节点指向当前节点的右子节点
            右子树: 2.当前节点是父节点的左子节点:
                        1.当前节点的右子节点的父节点指向当前节点的父节点
                        2.当前节点的父节点的左子树指向当前节点的右子节点
                   3.当前节点是父节点的右子节点:
                        1.当前节点的右子节点的父节点指向当前节点的父节点
                        2.当前节点的父节点的右子树指向当前节点的右子节点'''
                if currentNode.isRoot():
                    self.root = currentNode.rightChild
                elif currentNode.isLeftChild():
                    currentNode.rightChild.parent = currentNode.parent
                    currentNode.parent.leftChild = currentNode.rightChild
                else:
                    currentNode.rightChild.parent = currentNode.parent
                    currentNode.parent.rightChild = currentNode.rightChild

    def findSuccessor(self, currentNode): #当前节点有两棵子树
        current = currentNode.rightChild
        while current.hasLeftChild(): #一直往左走,找到key最小的current
            current = current.leftChild
        return current

    def spliceOut(self, succ): #当前节点有两棵子树
        '''移除的节点要不没有子节点,要不只有右子树
                移除的节点是左子节点:
                    1.移除的节点是叶节点:移除节点的父节点的左子树设为None
                    2.移除的节点是右节点:
                            1.移除节点的右子节点的父节点指向移除节点的父节点
                            2.移除节点的父节点的左子树指向移除节点的右子树'''
        if succ.isLeftChild():
            if succ.isLeaf():
                succ.parent.leftChild = None
            else:
                succ.rightChild.parent = succ.parent
                succ.parent.leftChild = succ.rightChild
        else:
            '''移除的节点是右子节点:
                    1.移除的节点是叶节点:移除节点的父节点的右子树设为None
                    2.移除的节点是右节点:
                            1.移除节点的右子节点的父节点指向移除节点的父节点
                            2.移除节点的父节点的右子树指向移除节点的右子树'''
            if succ.isLeaf():
                succ.parent.rightChild = None
            else:
                succ.rightChild.parent = succ.parent
                succ.parent.rightChild = succ.rightChild

测试用例(建议读者自己设置测试用例)

if __name__ == '__main__':
    # import random
    # list = []
    # for i in range(10):
    #     list.append(random.randint(0,100))
    # print(list)
    BT = BinarySearchTree()
    for i in [57,36,89,7,43,65,96,18,52,60,74]:
        BT.__setitem__(i, i)
    # if BT.__contains__(10):
    #     print(BT.__getitem__(10))
    # BT.__delitem__(57)
    BT.Traversal()

第三部分 递归迷宫

list1 = [1,1,1,1,1,1,1,1,1,1,1,1,1,1]
list2 = [1,0,0,0,1,1,0,0,0,1,0,0,0,1]
list3 = [1,0,1,0,0,0,0,1,0,1,0,1,0,1]
list4 = [1,0,1,0,1,1,1,1,0,1,0,1,0,1]
list5 = [1,0,1,0,0,0,0,0,0,1,1,1,0,1]
list6 = [1,0,1,1,1,1,1,1,1,1,0,0,0,1]
list7 = [1,0,1,0,0,0,0,0,0,0,0,1,0,1]
list8 = [1,0,0,0,1,1,1,0,1,0,1,1,0,1]
list9 = [1,0,1,0,1,0,1,0,1,0,1,0,0,1]
list10= [1,0,1,0,1,0,1,0,1,1,1,1,0,1]
list11= [1,0,1,0,0,0,1,0,0,1,0,0,0,1]
list12= [1,1,1,1,1,1,1,1,1,1,1,1,1,1]
maze = [list1,list2,list3,list4,list5,list6,list7,list8,list9,list10,list11,list12]
dirs = [(0,1), (1,0), (0,-1), (-1,0)]   #0右 1下 2左 3上
def mark(maze, pos):  #标记已经走过的路
    maze[pos[0]][pos[1]] = 2
def passable(maze, pos):   #检查是否可以行进
    return maze[pos[0]][pos[1]] == 0
#基于栈的迷宫求解算法
from Stack import Stack
def maze_solver(maze, start, end):
    if start == end:
        print(start)
        return
    st = Stack()
    mark(maze, start)
    st.push((start, 0))
    while not st.isEmpty():
        pos, nxt = st.pop()    #出栈
        for i in range(nxt, 4): #0右 1下 2左 3上
            nextp = (pos[0] + dirs[i][0],pos[1] + dirs[i][1])
            if nextp == end:
                st.push((pos,i))
                st.push(end)
                print(st.elem)
                return
            if passable(maze, nextp):
                st.push((pos, i))  #记录该点的行进方向
                mark(maze, nextp)      #标记已经走过的点
                st.push((nextp, 0))  #下一个点入栈
                break
    print('No path found')
maze_solver(maze, (1,1), (10,12))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胆怯与勇敢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值