a*算法流程图_03 Python 数据结构及算法

301 什么是线性结构

什么是线性结构 Linear Structure

  • 线性结构是一种有序数据项的集合, 其中每个数据项都有唯一的前驱和后继.
  • 线性结构总有两端, 在不同情况下, 两端的称呼也不同
  • 不同线性结构的关键在于数据项增减的方式
  • 学习四个简单但功能强大的线性数据结构: 栈 Stack、队列 Queue、双端队列 Deque 和列表 List
  • 应用广泛
  • 出现在各种算法中, 可以解决大量重要问题

302 栈抽象数据类型及 Python 实现

栈 Stack: 啥是栈?

  • 一种有次序的数据项集合, 在栈中, 数据项的加入和移除都仅发生在同一端
  • 日常生活中的栈: 书堆等
  • 距离栈底越近的数据项, 留在栈中的时间就越长
  • 这种次序称称为"先进先出LIFO", Last in First out

栈的特性: 反转次序

  • 进栈和出栈次序正好反转

抽象数据类型 Stack

  • 抽象数据类型"栈"是一个有次序的数据集, 每个数据项仅从"栈顶"一端加入到数据集中, 从数据集中移除, 栈具有后进先出的 LIFO 的特性
  • 抽象数据类型"栈"定义为如下操作: ++ Stack(): 创建一个空栈, 不包含任何数据项 ++ push(item): 将 item 加入栈顶, 无返回值 ++ pop(): 将栈顶数据项移除, 并返回, 栈被修改 ++ peek(): 窥视栈顶数据, 并返回栈顶的数据但不移除, 栈不被修改 ++ isEmpty(): 返回栈是否为空栈 ++ size(): 返回栈中有多少个数据项

用 Python 实现 ADT Stack

  • 在定义抽象数据类型 Stack 之后, 看一下如何利用 Python 实现
  • 基于 Python 的面向对象编程, 可以用来实现用户自定义数据类型

课程配套代码: pythonds 模块

调用方法:

from pythonds.basic.stack import Stack
# ADT Stack
# 将 list 末尾作为栈底
class Stack(object):
    def __init__(self):
        self.items = []
    
    def isEmpty(self):
        return self.items == []
    
    def push(self, item):
        self.items.append(item)
        
    def pop(self):
        return self.items.pop()
    
    def peek(self):
        return self.items[len(self.items)-1]
    
    def size(self):
        return len(self.items)
s = Stack()

print(s.isEmpty())
True
s.push(4)
s.push('dog')
print(s.peek())
dog
s.push(True)
print(s.size())
3
print(s.isEmpty())
False
s.push(8.8)
print(s.pop())
8.8
print(s.pop())
True
print(s.size())
2

ADT Stack 的另一端实现

  • 若将 list 的另一端作为 Stack 的栈顶, 同样也可以实现 Stack
  • 不同实现方案保持了 ADT 接口的稳定性, 性能有所不同
class Stack(object):
    def __init__(self):
        self.items = []
        
    def isEmpty(self):
        return self.items == []
    
    # 复杂度为 O(n)
    def push(self, item):
        self.items.insert(0, item)
    
    # 复杂度为 O(n)
    def pop(self):
        return self.items.pop(0)
    
    def peek(self):
        return self.items.pop(0)
    
    def peek(self):
        return len(self.items)

303 栈的应用: 简单括号匹配

栈的应用: 简单括号匹配

  • 如何构造匹配识别算法: 从左到右扫描括号串, 最新打开的左括号要匹配最后打开的右括号, 这种次序反转的识别, 符合栈的特性.

识别算法流程图为

138b4b977db7b29f7ba7110d7b71cd1f.png
括号识别算法流程图
from pythonds.basic.stack import Stack

def parChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index 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
    
print(parChecker("()()()()()((()))"))
True
print(parChecker('((())'))
False

更多的括号匹配

  • 在实际应用中, 会碰到更多的括号, 如 "[]", "{}".
  • 这些括号可能混在一起用
  • 注意整个字的开闭匹配情况

通用括号匹配算法: 代码

from pythonds.basic.stack import Stack

def parChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index 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)
    
    
print(parChecker('{([])}{}{}[({})]'))
True

304 栈的应用: 十进制转换为二进制

十进制转换为二进制

  • 二进制是计算机中最基本的概念, 其输入和输出仅为两种情况: 0 和 1
  • 对我们人而言, 十进制似乎更为常用.
  • x 进制的概念: 例如
  • 十进制数转换为二进制数可以利用"除以2求余数"的算法求解
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(52))
110100

扩展到更多进制转换

  • 将"除以2求余数"算法改为"除以N求余数"算法
  • 计算机的另外两种进制是八进制和十六进制

十进制转换为十六以下的任意进制: 代码

from pythonds.basic.stack import Stack

def baseConverter(decNumber, base):
    digits = "0123456789ABCDEF"
    
    remstack = Stack()
    
    while decNumber > 0:
        rem = decNumber % base
        remstack.push(rem)
        decNumber = decNumber // base
        
    newString = ""
    while not remstack.isEmpty():
        newString = newString + digits[remstack.pop()]
        
    return newString

print(baseConverter(25, 2))
print(baseConverter(25, 16))
print(baseConverter(666, 16))
11001
19
29A

305 表达式的转换(上)

中缀表达式

  • B * C 表示 B 乘以 C
  • 这种操作符(operator)介于操作数(operand)中间的表示方法叫做"中缀"表示法
  • 中缀表示法有时会会引起混淆, 例如 A + B * C
  • 为了消除这种混淆, 可以引入操作符的"优先级"
  • 引入括号表示强制优先级

全括号中缀表达式

  • 好处是便于计算机处理
  • 引入全括号表达式, 即在所有表达式的两边都加上括号. 例如 A+BC+D 即((A+(BC)+D))

前缀和后缀表达式

  • 中缀表达式 A+B 改成前缀即, +AB; 改成后缀表达式即 AB+
  • 移动操作符的位置, 即得到前缀和后缀表达式两种表示方法
  • A+B * C 的前缀表达式为 +ABC, 后缀表达为 ABC+

306 表达式转换(下)

通用的中缀转后缀算法

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 "012345679":
            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)

print(infixToPostfix("A+B*C"))
print(infixToPostfix("( A + B ) * C - ( D - E ) * ( F + G )"))
A+B*C
A B + C * D E - F G + * -

307 后缀表达式求值

后缀表达式求值

  • 作为栈结构的结束, 讨论"后缀表达式求值"问题
from pythonds.basic.stack import Stack

def postfixEval(postfixExpr):
    operandStack = Stack()
    tokenList = postfixExpr.split()
    
    for token in tokenList:
        if token in "0123456789":
            operandStack.push(int(token))
        else:
            operand2 = operandStack.pop()
            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
    
print(postfixEval('7 8 + 3 2 + /'))
3.0
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值