[Python] 数据结构与算法笔记(基本结构和递归)

1.基本结构

线性数据结构

1.1 栈

“后进先出 LIFO” 进栈和出栈的顺序正好相反
e.g. 浏览器的后退,word的undo
抽象数据类型“栈”是一个有次序的数据集,每个数据项仅从“栈顶”一端加入到数据集中、从数据集中移除,栈具有后进先出LIFO的特性。
在这里插入图片描述

1.1.1 栈的操作

基本操作:
在这里插入图片描述
操作例子:
在这里插入图片描述
在这里插入图片描述

Stack测试代码:

from pythonds.basic.stack import Stack

s = Stack()

print(s.isEmpty())
s.push(4)
s.push('dog')
print(s.peek())
s.push(True)
print(s.size())
print(s.isEmpty())
s.push(8.4)
print(s.pop())
print(s.pop())
print(s.size())

result:

True
dog
3
False
8.4
True
2

1.1.2 栈的应用——简单括号匹配

from pythonds.basic.stack import Stack

def perChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index < len(symbolString) and balanced:
        symbol = symbolString[index]
        if symbol == '(':
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced = False
            else:
                s.pop()

        index += 1

    if balanced and s.isEmpty():
        return True
    else:
        return False

实际应用中,会碰到更多种括号
python中的list [],dict {},tuple和表达式 ()。

def perChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index < len(symbolString) and balanced:
        symbol = symbolString[index]
        if symbol in '([{':         #加上多个左括号
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced = False
            else:
                # 括号匹配
                top = s.pop()
                if not matches(top, symbol):
                    balanced = False

        index += 1

    if balanced and s.isEmpty():
        return True
    else:
        return False


def matches(open, close):       #匹配
    opens = '([{'
    closers = ')]}'
    return opens.index(open) == closers.index(close)	#通过索引进行匹配

1.1.3 栈的应用——十进制转换成二进制

在这里插入图片描述

from pythonds.basic.stack import Stack

def divideBy2(decNumber):
    remstack = Stack()

    while decNumber > 0:
        rem = decNumber % 2
        remstack.push(rem)
        decNumber = decNumber // 2   # // 整数除

    binString = ""
    while not remstack.isEmpty():
        binString = binString + str(remstack.pop())

    return binString

print(divideBy2(42))

扩展:十六进制

from pythonds.basic.stack import Stack

def baseConverter(decNumber, base):
    digits = "0123456789ABCDEF"  #十六进制
    remstack = Stack()

    while decNumber > 0:
        rem = decNumber % base          #base为进制
        remstack.push(rem)
        decNumber = decNumber // base

    newString = ""
    while not remstack.isEmpty():
        newString = newString + digits[remstack.pop()]  # 如:pop()出14,则查表得到E

    return newString

print(baseConverter(25,16))
print(baseConverter(25,2))

1.1.4 栈的应用——表达式转换

中缀表达式
前缀表达式
后缀表达式
在这里插入图片描述

算法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

from pythonds.basic.stack import Stack

def infixToPostfix(infixexpr):
    prec = {}       #记录操作符优先级
    prec['*'] = 3
    prec['/'] = 3
    prec['+'] = 2
    prec['-'] = 2
    prec['('] = 1

    opStack = Stack()
    postfixList = []
    tokenList = infixexpr.split()       #解析表达式到单词列表

	# 扫描
    for token in tokenList:
        if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789":
            postfixList.append(token)
        elif token == '(':
            opStack.push(token)
        elif token == ')':
            topToken = opStack.pop()
            while topToken != '(':
                postfixList.append(topToken)
                topToken = opStack.pop()
        else:
            while ( not opStack.isEmpty()) and (prec[opStack.peek() ] >= prec[token]):
                postfixList.append(opStack.pop())
            opStack.push(token)

    while not opStack.isEmpty():
        postfixList.append(opStack.pop())
    return " ".join(postfixList)		#合成后缀表达式字符串

后缀表达式求值
在这里插入图片描述

from pythonds.basic.stack import Stack

def postfixEval(postfixExper):
    operandStack = Stack()
    tokenList = postfixExper.split()   

    for token in tokenList:
        if token in  "0123456789":
            operandStack.push(int(token))
        else:
            operand2 = operandStack.pop()       #从栈顶弹出2个操作数,先弹出的是右操作数,后弹出的是左操作数。
            operand1 = operandStack.pop()       
            result = doMath(token,operand1,operand2)
            operandStack.push(result)
    return operandStack.pop()

def doMath(op, op1, op2):
    if op == '*':
        return op1 * op2
    elif op == '/':
        return op1 / op2
    elif op == '+':
        return op1 + op2
    else:
        return op1 - op2

1.2 队列

“先进先出 FIFO”
e.g. 进程调度(进程数远多于CPU核心数,有些进程还要等待不同类型I/O事件),打印机,键盘缓存

1.2.1 队列的操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2.2 队列的应用——热土豆问题

from pythonds.basic.queue import Queue

def hotPotato(namelist, num):
    simqueue = Queue()
    for name in namelist:
        simqueue.enqueue(name)

    while simqueue.size() > 1:	#循环到队列只剩一个
        for i in range(num):   #队首出队,再入队,共循环num次
            simqueue.enqueue(simqueue.dequeue())
        simqueue.dequeue()	#队首出队

    return simqueue.dequeue() 	#最后唯一一个出队输出

# 传递固定人数,7
print(hotPotato(['Bill','David','Susan','Jane','Kent','Brad'],7))

1.2.3 队列的应用——打印任务

from pythonds.basic.queue import Queue
import random

class Printer:
    def __init__(self, ppm):
        self.pagerate = ppm         #打印速度
        self.currentTask = None     #打印任务
        self.timeRemaining = 0      #任务倒计时

    def tick(self):         #打印1秒
        if self.currentTask != None:
            self.timeRemaining = self.timeRemaining - 1
            if self.timeRemaining <= 0:
                self.currentTask = None

    def busy(self):     #打印忙?
        if self.currentTask != None:
           return True
        else:
           return False

    def startNext(self,newtask):        #打印新任务
       self.currentTask = newtask
       self.timeRemaining = newtask.getPages() * 60/self.pagerate


class Task:
    def __init__(self,time):
        self.timestamp = time       #生成时间戳
        self.pages =random.randrange(1,21)      #打印页数
 
    def getStamp(self):
        return self.timestamp
 
    def getPages(self):
        return self.pages
 
    def waitTime(self,currenttime):
        return currenttime -self.timestamp      #等待时间

 
def newPrintTask():
    num =random.randrange(1,181)        #1/180概率生成作业
    if num == 180:
        return True
    else:
        return False

def simulation(numSeconds, pagesPerMinute):     #模拟
 
    labprinter =Printer(pagesPerMinute)
    printQueue = Queue()
    waitingtimes = []
 
    for currentSecond in range(numSeconds):
 
      if newPrintTask():
          task =Task(currentSecond)
          printQueue.enqueue(task)
 
      if (not labprinter.busy()) and (not printQueue.isEmpty()):
          nexttask =printQueue.dequeue()
          waitingtimes.append(nexttask.waitTime(currentSecond))
          labprinter.startNext(nexttask)
 
      labprinter.tick()

    averageWait=sum(waitingtimes)/len(waitingtimes)
    print("Average Wait %6.2f secs %3d tasks remaining."%(averageWait,printQueue.size()))
 



#模拟10次,每次3600s,打印机每分钟5页
for i in range(10):
    simulation(3600,5)


Average Wait 120.17 secs 0 tasks remaining.
Average Wait 256.60 secs 2 tasks remaining.
Average Wait 48.81 secs 0 tasks remaining.
Average Wait 142.91 secs 2 tasks remaining.
Average Wait 113.92 secs 1 tasks remaining.
Average Wait 22.40 secs 2 tasks remaining.
Average Wait 119.29 secs 0 tasks remaining.
Average Wait 163.48 secs 1 tasks remaining.
Average Wait 133.04 secs 0 tasks remaining.
Average Wait 68.75 secs 0 tasks remaining.

1.3 双端队列抽象数据类型及Python实现+回文词判定

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
应用:“回文词”判定

from pythonds.basic.deque import Deque

# 判断是否是回文词
def back_to_word_check(s1):
	deque = Deque()								#实例化双端队列
	[deque.addRear(i) for i in s1]				#将字符串从队尾入队
	while deque.size() > 1:						#队列长度>1,则循环,否则为0或1个,则说明是回文词
		first = deque.removeFront()				#从队首出队一个
		last = deque.removeRear()				#从队尾出队一个
		if first != last:						#若不相同,则
			return False 						#非回文词
	return True 								#回文词

s1 = '枯眼望遥山隔水往来曾见几心知壶空怕酌一杯酒笔下难成和韵诗途路阻人离别久讯音无雁寄回迟孤灯夜守长寥寂夫忆妻兮父忆儿儿忆父兮妻忆夫寂寥长守夜灯孤迟回寄雁无音讯久别离人阻路途诗韵和成难下笔酒杯一酌怕空壶知心几见曾来往水隔山遥望眼枯'
print(back_to_word_check(s1))

1.4 无序表抽象数据类型及Python实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.5 有序表抽象数据类型及Python实现

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2 递归

2.1 递归与实现

将问题分解为规模更小的相同问题
在这里插入图片描述
递归实现:
在这里插入图片描述
递归深度限制,防止无限递归。

import sys

sys.getrecursionlimit()		#默认限制递归1000

sys.getrecursionlimit(3000)		#限制递归3000次

2.2 递归的应用——任意进制转换

def toStr(n,base):
    convertString = "0123456789ABCDEF"
    if n < base:
        return convertString[n]     #最小规模
    else:
        return toStr(n//base,base) + convertString[n%base]      #减小规模,调用自身

print(toStr(1453,16))   #将1453转换成16进制

2.3 递归可视化

2.3.1 分形树

在这里插入图片描述
e.g.
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

2.3.2 谢尔宾斯基三角形

在这里插入图片描述

2.4 递归的应用——汉诺塔

在这里插入图片描述

def moveTower(height, fromPole, withPole, toPole):
    if height >= 1:
        moveTower(height - 1, fromPole, toPole, withPole)
        moveDisk(height, fromPole, toPole)
        moveTower(height - 1, withPole, fromPole, toPole)

def moveDisk(disk, fromPole, toPole):
    print(f"Moving disk[{disk}] from {fromPole} to {toPole}")

moveTower(3, "#1", "#2", "#3")

Moving disk[1] from #1 to #3
Moving disk[2] from #1 to #2
Moving disk[1] from #3 to #2
Moving disk[3] from #1 to #3
Moving disk[1] from #2 to #1
Moving disk[2] from #2 to #3
Moving disk[1] from #1 to #3

几个小算法

读取以空格分隔的一行整数

input 3个数:

# input 3个数
a,b,c = map(int, input().split())

input 未知个数:

# input未知个数
op = map(int, input().split())
l = []
l=[i for i in op]
print(min(l))

将list中的string转换为int

假设有这样一个
results = [‘1’, ‘2’, ‘3’]
转化为下面这个样子
results = [1, 2, 3]

results = list(map(int, results))

洗盘子

在这里插入图片描述

from pythonds.basic.stack import Stack

def washdishes(nums):
    s = Stack()
    index = 0
    l = []

    for num in nums:
        if s.isEmpty() or s.peek() < num:
            s.push(num)
            l.append(num)
        elif s.peek() > num and num+1 in l:
            s.push(num)
            l.append(num)
        else:
            return 'No'
            break
    return 'Yes'

int()进制转换

    num = int(str(num), base=m) #将m进制的num转换成十进制

进制转换表:

2进制8进制10 进制16进制
2进制-bin(int(x,8))bin(int(x,10))bin(int(x,16))
8进制oct(int(x,2))-oct(int(x,10))oct(int(x,16))
10进制str(int(x,2))str(int(x,8))-str(int(x,16))
16进制hex(int(x,2))hex(int(x,8)hex(int(x,10))-
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值