【可与python】数据结构与算法实现,内含思路讲解

本文详细介绍了数据结构中的栈和队列,包括它们的定义、操作及应用场景,如括号匹配、十进制转二进制、中缀表达式等。同时,深入探讨了递归的概念,展示了递归在图形绘制(如螺旋线、分形树)和复杂问题(如汉诺塔、迷宫探索)中的应用。此外,还涵盖了动态规划在找零兑换问题和背包问题的解决方案。
摘要由CSDN通过智能技术生成

往期内容:

关注我,持续更新本篇内容!有想要看的部分可以评论区留言

线性结构

有唯一前驱和后继,两端

栈(stack) Last in Firts out (LIFO)

特性:次序反转
举例:undo,back操作

操作

  • Stack() 创建栈
  • push(item) 加入栈顶
  • pop()移除
  • peek()查看栈顶
  • isEmpty() 是否空栈
  • size() 栈的大小

python 中 可以将list右端看作栈顶

class Stack():
    '''将list [-1]作为栈顶,比选择[0]做栈顶更快(时间复杂度)'''  
    # -  Stack() 创建栈
    # - push(item) 加入栈顶
    # - pop()移除栈顶元素
    # - peek()查看栈顶
    # - isEmpty() 是否空栈
    # - size() 栈的大小
    def __init__(self):
        self.items=[]
    def push(self,item):
        self.items.append(item)
    def pop(self):
        self.items.pop()
    def peek(self):
        return self.items[-1]
    def isEmpty(self):
        return self.items==[]
    def size(self):
        return len(self.items)

栈的简单应用

括号匹配

例如[[][[]][][][]]
从左到右扫描,左括号加入栈顶,右括号与栈顶匹配
结束条件:不匹配、扫描完成后没有右括号但栈不为空

十进制转换为二进制

对二求余数不断求余数后的每一个数放在栈里push,求完后pop每一个数
注意最先求出的数实际上是最低位数,例如4的二进制是100,最后求出的是1但是1最先出,所以满足栈,

中缀表示法

A+BC 优先级
括号 强制优先级
全括号表达式 (A+(B
C))

中缀表示: A+B
前缀表示: +AB
后缀表示: AB+

中缀表示: A+B*C
前缀表示: +A*BC
后缀表示: ABC*+

中缀表示:(A+B)*C
后缀表示: AB+C*

在全括号表达式 (A+(B*C)) 将*移动至其左括号匹配的)处将其替代并去掉*对应的),则有(A+BC*) 后缀表达式的第一步,以此类推

没有括号时,中缀表示: A+B*C,虽然+先出现但是优先级比*低,所以先保存到栈里,等*处理完最后输出,

若遇到的下一个运算符更低或遇到右括号,直接输出,若不低则进入栈,

代码中用字典保存优先级,例如p={‘*’:2,“+”:1}

后缀表达式求值

操作符只作用于离他最近的操作数,所以最后入栈的AB先计算

队列(Queue) First in First out (FIFO)

操作

  • Queue() 创建队列
  • enqueue(item) 加入队列
  • dequeue()队首移除
  • isEmpty() 是否空
  • size() 大小
class Queue():
    '''将list [-1]作为首端'''
    # -  Queue() 创建队列
    # - enqueue(item) 加入队列
    # - dequeue()队首移除
    # - isEmpty() 是否空
    # - size() 大小
    def __init__(self):
        self.items=[]
    def enqueue(self,item):
        self.items.insert(0,item)
        #0()n复杂度
    def dequeue(self):
        self.items.pop()
    def isEmpty(self):
        return self.items==[]
    def size(self):
        return len(self.items)

队列的简单应用

约瑟夫问题
打印队列

双端队列Deque

两端都可进可出

  • Deque()
  • addFront()
  • addRear()
  • removeFront()
  • removeRear()
  • isEmpty()
  • size()

列表

(无序表)相关位置

  • List()
  • add(item) ======> insert(4,item),append(item)
  • remove(item) ===> pop(index(item)),pop()
  • search(item) ===> index(item)
  • isEmpty()
  • size()

无序列表:链表

表头…–>C—>B---->A—>|尾
新加入F
表头…F—>C—>B---->A—>|尾

利用节点实现

class Node():
    # 链表准备工作
    def __int__(self,initdata):
        self.data = initdata
        self.next = None
    def getData(self):
        return self.data
    def getNext(self):
        return self.next
    def setData(self,newdata):
        self.data = newdata
    def setNext(self,newnext):
        self.next = newnext

class UnorderedList():
    def __init__(self):
        self.head = None
    def isEmpty(self):
        return self.head == None

    def add(self,item):
        temp = Node(item)
        temp.setNext(self.head)
        self.head = temp

    def size(self):
        current = self.head
        count = 0
        while current != None:
            count = count + 1
            current = current.getNext()

        return count

    def search(self,item):
        current = self.head
        found = False
        while current !=None and not found:
            if current.getData()==item:
                found = True
            else:
                current = current.getNext()

        return found

    def remove(self,item):
        # 如果current是要删除的节点,则将current前一个节点的next连接到current的后一个节点,也就是previous,
        # 如果previous后一个节点是None,也就是表头,那么current的前一个节点直接连接到表头
        previous = self.head
        current = None
        found = False
        while not found:
            if current.getData() == item:
                found = True
            else:
                previous = current
                current = current.getNext()
        if previous == None:
            self.head = current.getNext()    #None-->found--->B-->A---|         None--->B--->A--->|
        else:
            # None--> C -->found - -->B -->A - -- |      None--> C -->B -->A - -- |
            previous.setNext = current.getNext()
        return found

有序表

依照可比性质排列
例如:
表头…–>9—>5---->3—>|尾

递归

将问题分解为规模更小的相同问题
调用自身

# 前n项和
def n_sum(n):
    while n==1:
        return 1
    else:
        return n+n_sum(n-1)
print(n_sum(6))

规律

  1. 基本结束条件(最小规模问题直接解决)
  2. 算法必须改变状态向基本结束条件演进(减小问题规模)
  3. 递归算法必须调用自身(解决减小了规模的相同问题)

修改系统递归最大值

# 在python中内置的sys模块可以获取和调整最大递归深度
import sys
sys.getrecursionlimit()  # 返回 1000
sys.setrecursionlimit(3000) # 此时修改为3000

递归图形

使用turtle作图

螺旋线

import turtle
t = turtle.Turtle()

def drawSpiral(t,linelen):
    if linelen >0:
        t.forward(linelen)
        t.right(90)
        drawSpiral(t,linelen-5)

drawSpiral(t,100)
turtle.done()

分形树(自相似递归图形)

分形Fractal

t = turtle.Turtle()
def tree(brach_len):
    if brach_len>=5:          #树干太短结束
        t.forward(brach_len)  #画树干
        t.right(20)
        tree(brach_len-15)
        t.left(40)
        tree(brach_len - 15)
        t.right(20)   #回正
        t.backward(brach_len)   #退回原位置
t.left(90)
t.penup()
t.backward(100)  #画笔起始在中央,penup走的时候不留痕迹到底边
t.speed(1)
# “fastest”: 0 最快
# “fast”: 10 快
# “normal”: 6 正常
# “slow”: 3 慢
# “slowest”: 1 最慢
# 速度值从 1 到 10,画线和海龟转向的动画效果逐级加快
t.pendown()
t.pencolor("green")
t.pensize(2)
tree(70)
t.hideturtle()
turtle.done()

谢尔宾斯基Sierpinski 三角形

分形构造,对等边三角形中间挖空,挖空后对其余三角形重复以上操作
面积为0,周长无穷,介于1维与2维之间的分数维(约1.585维)构造

from turtle import*
def drawTriangle(points,color, myTurtle):
    myTurtle.fillcolor(color)
    myTurtle.up( )
    myTurtle.goto(points[0])
    myTurtle.down( )
    myTurtle.begin_fill()
    myTurtle.goto(points [1])
    myTurtle.goto(points[2])
    myTurtle.goto(points[0])
    myTurtle.end_fill()
def getMid(p1, p2):
    return ( (p1[0] +p2[0])/2,(p1[1] + p2[1]) / 2)
def sierpinski(points,degree,myTurtle) :
    colormap = [ 'blue', 'red' , 'green' , 'white', 'yellow',
    'violet' , 'orange' ]
    drawTriangle(points, colormap[ degree] , myTurtle)
    if degree > 0 :
        sierpinski( [points [0],
            getMid(points [0], points [1]),getMid(points[0], points[2])],degree-1,myTurtle)
        sierpinski( [points[1],
            getMid(points [0], points[1]),getMid(points [1], points[2])],degree-1, myTurtle)
        sierpinski( [points[2],
            getMid(points[2], points[1]),getMid(points[0], points [2])],degree-1,myTurtle)
myTurtle = Turtle( )
mywin = myTurtle.getscreen( )
myPoints = [ (-500,-250),(0,500),(500,-250)]
sierpinski(myPoints, 5,myTurtle)
mywin.exitonclick( )

复杂递归问题

汉诺塔问题

#汉诺塔问题
def moveTower(height, fromPole,withPole,toPole):
    if height >=1:
        moveTower(height-1,fromPole,toPole,withPole)  #把最大disk上的tower(不包含最大的disk)从from挪到withPole
        moveDisk(height,fromPole,toPole)     #挪动最大的的disk(用此时的总高度表示最底层disk)到toPole
        moveTower(height-1,withPole,fromPole,toPole)
def moveDisk(disk,fromPole,toPole):
    print(f"move {disk} from {fromPole} to {toPole}")

moveTower(2,"A","B","C")

探索迷宫

分治策略

优化(贪心、递归、动态规划)

找零兑换问题

贪心策略解法

每次一尽量大的一部分对应到兑换硬币问题,每次以最多数量的最大面值来迅速减少找零面值

递归解法

从最大问题往上递推

def recMC(coinValuelist,change):
    minCoins = change
    if change in coinValuelist:  
        return 1
    else:

        return 1+min([ recMC(coinValuelist,change-k) for k in coinValuelist if k < change  ]  )  #k<change,把硬币大于面值的去掉
        # 不懂的话使用以下代码
        # for i in [k for k in coinValuelist if k<change]:   #硬币面值小于change的硬币面值集合
        #     numCoins = 1 + recMC(coinValuelist,change-i)
        #     if numCoins < minCoins:
        #         minCoins = numCoins
        # return minCoins


print(recMC([1,5,10,25],63))
#耗时长! 重复计算!

加入记录表memo

def recMC(coinValuelist,change,knownResults):
    minCoins = change
    if change in coinValuelist:
        knownResults[change] =1
        return 1
    elif knownResults[change]>0:
        return knownResults[change]    #记录表,避免重复计算
    else:
        for i in [k for k in coinValuelist if k<change]:   #硬币面值小于change的硬币面值集合
            numCoins = 1 + recMC(coinValuelist,change-i,knownResults)
            if numCoins < minCoins:
                minCoins = numCoins
                knownResults[change]=minCoins
        return minCoins


print(recMC([1,5,10,25],63,knownResults=[0]*64))

动态规划解法

大问题的最优解包含每一个更小问题的最优解
从最小问题推到最大问题
对于找零问题,change为1一直往上推

def dynMC(coinValuelist,change,knownResults):
    for cents in range(1,change+1):
        minCoints = cents    #初始化一个最大值
        for i in [k for k in coinValuelist if k<= cents]:  #硬币面值小于change的硬币面值集合, 找零一次后的所有出路
            if knownResults[cents-i]+1 < minCoints:       #上面完成1次找零,这里加1
                minCoints = knownResults[cents-i]+1
        knownResults[cents] = minCoints
    return knownResults[change]

print(dynMC([1,5,10,21,25],63,knownResults=[0]*64))

回溯输出

def dynMC(coinValuelist,change,knownResults,coinsUsed):
    for cents in range(1,change+1):
        minCoints = cents    #初始化一个最大值
        newCoin = 1   #初始化新的硬币
        for i in [k for k in coinValuelist if k<= cents]:  #硬币面值小于change的硬币面值集合, 找零一次后的所有出路
            if knownResults[cents-i]+1 < minCoints:       #上面完成1次找零,这里加1
                minCoints = knownResults[cents-i]+1     #记录最小coints使用
                newCoin = i                            #记录对应面值
        knownResults[cents] = minCoints
        coinsUsed[cents] = newCoin      #记录本次新加的硬币
    return knownResults[change]

print(dynMC([1,5,10,21,25],63,knownResults=[0]*64,coinsUsed=[0]*64))

def printCoins(coinUsed, change):
    coin = change
    while coin>0:
        thisCoin = coinUsed[coin]
        print(thisCoin)
        coin = coin-thisCoin

背包问题

动态规划

item | weight | value
1 | 2 | 3
2 | 3 | 4
3 | 4 | 8
4 | 5 | 8
5 | 9 | 10

限制weight<=20
求最大value

思路:
设m(i,w)为装i个物品,共重w时的价值
tr[i]={“w”:w_i ,“v”:v_i} 为第i个物品的weight和value
则:

m(i,w)=

  • 0, i=0
  • 0, w=0
  • m(i-1,w),w_i > w 即当装第i件物品,但第i件大于背包承重,所以没有转
  • max(m(i-1,w),m(i-1,w-w_i)+v_i), otherwise 即当装或不装第i件物品
tr = [None,{"w":2,"v":3},{"w":3,"v":4},{"w":4,"v":8},{"w":5,"v":8},{"w":9,"v":10}]    # index==0设置为None,与item编号对齐

max_W = 20      # 背包最大承重

m = {(i,w):0 for i in range(len(tr)) for w in range(max_W+1)}    #初始化所有的value值为0
#注意这时包括了思考的前两种情况

for i in range(1,len(tr)):  # 实际上len(tr)==5+1, 所以这里 [1,5],后面编号也i也就对应item[i],巧妙!
    for w in range(1,max_W+1):  #要包括最大承重本身
        if tr[i]["w"]>w:
            m[(i,w)]=m[(i-1,w)]
        else:
            m[(i,w)]= max(m[(i-1,w)],m[(i-1,w-tr[i]["w"])]+tr[i]["v"])

print(m[(len(tr)-1,max_W)])

未完待更…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可与很ok

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

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

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

打赏作者

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

抵扣说明:

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

余额充值