算法思想练习2(python)

广度优先搜索和深度优先搜索

上篇已经讲了广度优先与深度优先搜索,这边就写了,虽然说还可以有一些扩展,比如说算法导论里面说的什么 深度,广度优先搜索树, 它们的一些特点什么的, 反正我基本上没用到过,我也说不清。

树的三种遍历的实现

我想跟网上大部分写的不同一点,然后自己用数组模拟的二叉树(网上大部分都是模拟的指针)

代码:(重点在非递归。。都说所有的递归可以转成非递归,感觉好难转啊,不知道有没有什么套路)

class Tree:
    def __init__(self, lines = [0], ll = 1):
        self.lines = lines
        self.ll = ll
        
    def add(self, data):
        self.lines.append(data)
        self.ll += 1
        
    def front_dfs(self, k = 1):
        if (k >= self.ll):
            return ()
        state = (self.lines[k],) + self.front_dfs(k<<1) + self.front_dfs(k<<1|1)
        return state
    
    def middle_dfs(self, k = 1):
        if (k >= self.ll):
            return ()
        state = self.middle_dfs(k<<1) + (self.lines[k],) + self.middle_dfs(k<<1|1)
        return state
    
    def later_dfs(self, k = 1):
        if (k >= self.ll):
            return ()
        state = self.later_dfs(k<<1) + self.later_dfs(k<<1|1) + (self.lines[k],)
        return state
    #普通的用栈模拟递归 注意后进先出
    def front_stack1(self, k = 1):
        myStack = []
        myStack.append(k)
        state = ()
        while myStack:
            k = myStack.pop()
            state += (self.lines[k],)
            if k<<1|1 < self.ll: #右子树先进
                myStack.append(k<<1|1)
            if k<<1 < self.ll: #左子树再进
                myStack.append(k<<1)
            k = k<<1|1
        return state 
    
    #第二种就是下面写的中序遍历改一下输出位置
    def front_stack2(self, k = 1):
        myStack = []
        state = ()
        while k < self.ll or myStack:
            while k < self.ll:
                state += (self.lines[k],) #这里
                myStack.append(k)
                k <<= 1
            k = myStack.pop()
            k = k<<1|1
        return state        
    
    #中序遍历相当于。。。我反正说不清,反正就是可以
    def middle_stack(self, k = 1):
        myStack = []
        state = ()
        while k < self.ll or myStack:
            while k < self.ll:
                myStack.append(k)
                k <<= 1
            k = myStack.pop()
            state += (self.lines[k],) #这里
            k = k<<1|1
        return state 
    
    def later_stack1(self, k = 1):
        myState = []
        state = ()
        #pCur:当前访问节点,pLastVisit:上次访问节点 
        pLastVisit = 0
        pCur = k
        #先把pCur移动到左子树最下边 
        while pCur < self.ll:
            myState.append(pCur)
            pCur <<= 1
        while (len(myState) != 0):
            pCur = myState.pop()
            #一个根节点被访问的前提是:无右子树或右子树已被访问过 
            if pCur<<1|1 >= self.ll or pCur<<1|1 == pLastVisit:
                state += (self.lines[pCur],)
                pLastVisit = pCur
            else:
                #根节点再次入栈
                myState.append(pCur)
                pCur = pCur<<1|1
                #进入右子树,且可肯定右子树一定不为空
                while pCur < self.ll:
                    myState.append(pCur)
                    pCur <<= 1
        return state
    
    #后序遍历可以看成 先遍历根结点再右子树然后再左子树的 逆序
    def later_stack2(self, k = 1):
        state = ()
        myState = [1]
        while myState:
            k = myState.pop()
            state = (self.lines[k],) + state #逆序
            if k<<1 < self.ll:
                myState.append(k<<1)
            if k<<1|1 < self.ll:
                myState.append(k<<1|1)
        return state
    
x = Tree()
for i in range(10):
     x.add(i)
print(x.later_stack1())
print(x.later_stack2())

网上大神是模拟的用指针来表示二叉树的写法:(比较容易看懂)

class Node(object):
    """节点类"""
    def __init__(self, elem=-1, lchild=None, rchild=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild


class Tree(object):
    """树类"""
    def __init__(self):
        self.root = Node()
        self.myQueue = []

    def add(self, elem):
        """为树添加节点"""
        node = Node(elem)
        if self.root.elem == -1:  # 如果树是空的,则对根节点赋值
            self.root = node
            self.myQueue.append(self.root)
        else:
            treeNode = self.myQueue[0]  # 此结点的子树还没有齐。
            if treeNode.lchild == None:
                treeNode.lchild = node
                self.myQueue.append(treeNode.lchild)
            else:
                treeNode.rchild = node
                self.myQueue.append(treeNode.rchild)
                self.myQueue.pop(0)  # 如果该结点存在右子树,将此结点丢弃。


    def front_digui(self, root):
        """利用递归实现树的先序遍历"""
        if root == None:
            return
        print (root.elem,)
        self.front_digui(root.lchild)
        self.front_digui(root.rchild)


    def middle_digui(self, root):
        """利用递归实现树的中序遍历"""
        if root == None:
            return
        self.middle_digui(root.lchild)
        print (root.elem,)
        self.middle_digui(root.rchild)


    def later_digui(self, root):
        """利用递归实现树的后序遍历"""
        if root == None:
            return
        self.later_digui(root.lchild)
        self.later_digui(root.rchild)
        print (root.elem,)


    def front_stack(self, root):
        """利用堆栈实现树的先序遍历"""
        if root == None:
            return
        myStack = []
        node = root
        while node or myStack:
            while node:                     #从根节点开始,一直找它的左子树
                print (node.elem,)
                myStack.append(node)
                node = node.lchild
            node = myStack.pop()            #while结束表示当前节点node为空,即前一个节点没有左子树了
            node = node.rchild                  #开始查看它的右子树


    def middle_stack(self, root):
        """利用堆栈实现树的中序遍历"""
        if root == None:
            return
        myStack = []
        node = root
        while node or myStack:
            while node:                     #从根节点开始,一直找它的左子树
                myStack.append(node)
                node = node.lchild
            node = myStack.pop()            #while结束表示当前节点node为空,即前一个节点没有左子树了
            print (node.elem,)
            node = node.rchild                  #开始查看它的右子树


    def later_stack(self, root):
        """利用堆栈实现树的后序遍历"""
        if root == None:
            return
        myStack1 = []
        myStack2 = []
        node = root
        myStack1.append(node)
        while myStack1:                   #这个while循环的功能是找出后序遍历的逆序,存在myStack2里面
            node = myStack1.pop()
            if node.lchild:
                myStack1.append(node.lchild)
            if node.rchild:
                myStack1.append(node.rchild)
            myStack2.append(node)
        while myStack2:                         #将myStack2中的元素出栈,即为后序遍历次序
            print (myStack2.pop().elem,)


    def level_queue(self, root):
        """利用队列实现树的层次遍历"""
        if root == None:
            return
        myQueue = []
        node = root
        myQueue.append(node)
        while myQueue:
            node = myQueue.pop(0)
            print (node.elem,)
            if node.lchild != None:
                myQueue.append(node.lchild)
            if node.rchild != None:
                myQueue.append(node.rchild)


if __name__ == '__main__':
    """主函数"""
    elems = range(10)           #生成十个数据作为树节点
    tree = Tree()          #新建一个树对象
    for elem in elems:                  
        tree.add(elem)           #逐个添加树的节点

    print ('队列实现层次遍历:')
    tree.level_queue(tree.root)

    print ('\n\n递归实现先序遍历:')
    tree.front_digui(tree.root)
    print ('\n递归实现中序遍历:' )
    tree.middle_digui(tree.root)
    print ('\n递归实现后序遍历:')
    tree.later_digui(tree.root)

    print ('\n\n堆栈实现先序遍历:')
    tree.front_stack(tree.root)
    print ('\n堆栈实现中序遍历:')
    tree.middle_stack(tree.root)
    print ('\n堆栈实现后序遍历:')
    tree.later_stack(tree.root)

最小生成树实现


1. Prim算法

大概就是 假设边集u 是图G(V,E)中某个最小生成树的子集, 然后使用贪心策略选一条安全边加入, 直到选了 V-1条

跟单源最短路径里面的dijkstal算法很像

还记得上篇里的那5行代码吗:orz

代码:(复杂度为O(ElgV),如果使用斐波那契堆来实现优先队列Q的话会变成 O(E+Vlg(V)) )

from heapq import heappop, heappush  
 #G是用字典描述的邻接链表 
def prim(G, s):  
    P, Q = {}, [(0, None, s)]  
    while Q:  
        _, p, u = heappop(Q)#优先队列每次取短的那一条边  
        if u in P: continue
        P[u] = p  #标记u节点,并记录u的前驱结点
        #松弛操作
        for v, w in G[u].items():  
            heappush(Q, (w, u, v))  
    return P  

2.kruskal算法(实质也是贪心算法)

在图G(V,E)中先假设每个点都是独立的,也就是它们各自形成一棵树,一共有V颗。 

再按非递减的方式遍历所有的边,如果当前这条边属于两个不同的集合则,将这条边加入最小生成树,并将这两个集合合并。

代码:(复杂度O(ElgV))

#kruskal算法, 主要是并查集的应用
def find(C, u):
    if C[u] != u:
        C[u] = find(C, C[u])
    return C[u]

def union(C, R, u, v):
    u, v = find(C, u), find(C, v)
    if R[u] > R[v]:
        C[v] = u
    else:
        C[u] = v
    if R[u] == R[v]:
        R[v] += 1

def kruskal(G):
    E = [(G[u][v], u, v) for u in G for v in G[u]]
    T = set()
    C, R = {u: u for u in G}, {u: 0 for u in G}
    for _, u, v in sorted(E):
        if find(C, u) != find(C, v):
            T.add((u, v))
            union(C, R, u, v)
    return T




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值