栈与队列编程练习

本文介绍了几种典型的数据结构算法应用案例,包括中缀表达式求值、基数排序、HTML标记匹配等,并给出了详细的代码实现。

一.中缀表达式求值

问题:

通过把“中缀转后缀”和“后缀求值”两个算法功能集成在一起(非简单的顺序调用),
实现对中缀表达式直接求值,新算法还是从左到右扫描中缀表达式,
但同时使用两个栈,一个暂存操作符,一个暂存操作数,来进行求值。
创建一个函数,接受参数为一个字符串,即一个中缀表达式,
其中每个数字或符号间由一个空格隔开;
返回一个浮点数,即求值的结果。(支持 + - * / ^ 五种运算)
其中“ / ”定义为真除True DIV,结果是浮点数类型

代码:

class Stack:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.isEmpty():
            return self.items.pop()

    def peek(self):
        return self.items[len(self.items) - 1]

    def size(self):
        return len(self.items)


def calculate(s) -> float:
    def domath(op, op1: float, op2: float):  # 运算函数,加减乘除乘方
        if op == "*":
            return op1 * op2
        elif op == "/":
            return op1 / op2
        elif op == "+":
            return op1 + op2
        elif op == "-":
            return op1 - op2
        elif op == "^":  # ^
            return op1 ** op2

    def doOperand(op):  # 运算函数,计算栈内数
        op2 = operandStack.pop()
        op1 = operandStack.pop()
        result = domath(toptoken, op1, op2)
        operandStack.push(result)

    prec = {"^": 4, "*": 3, "/": 3, "+": 2, "-": 2, "(": 1}  # 运算符优先级
    opStack = Stack()        # 记录运算符号栈
    operandStack = Stack()     # 记录数字栈
    tokenlist = s.split()       # 所有符号
    for token in tokenlist:
        if token.isnumeric():
            operandStack.push(float(token))   # 添加数字入栈
        elif token == "(":
            opStack.push(token)        # 压入左括号
        elif token == ")":
            toptoken = opStack.pop()    # 读取到右括号时,提出一个运算符
            while toptoken != "(":         # 进行计算
                doOperand(toptoken)
                toptoken = opStack.pop()
        else:                          # token优先级更低时,先进行栈内的运算
            while (not opStack.isEmpty()) and (prec[opStack.peek()]) >= prec[token]:
                toptoken = opStack.pop()
                doOperand(toptoken)
            opStack.push(token)
    while not opStack.isEmpty():
            toptoken = opStack.pop()
            doOperand(toptoken)
    return operandStack.pop()
    # 代码结束

结果检验
输入:

# 调用检验
print("======== 1-calculate ========")
print(calculate("( 2 + 3 ) * 6 + 4 / 2"))
print(calculate("2 ^ 3 + 4 * 5 - 16 / 2"))
print(calculate("( 5 + 1 ) * 2 / 3 - 3 ^ ( 2 + 8 / 4 ) / 9 + 6"))

输出:

======== 1-calculate ========
32.0
20.0
1.0

二.基数排序

问题:
实现一个基数排序算法,用于10进制的正整数从小到大的排序。

思路是保持10个队列(队列0、队列1…队列9、队列main),开始,所有的数都在main队列,没有排序。
第一趟将所有的数根据其10进制个位(09),放入相应的队列09,全放好后,按照FIFO的顺序,将每个队列的数合并排到main队列。
第二趟再从main队列队首取数,根据其十位的数值,放入相应队列0~9,全放好后,仍然按照FIFO的顺序,将每个队列的数合并排到main队列。
第三趟放百位,再合并;第四趟放千位,再合并。
直到最多的位数放完,合并完,这样main队列里就是排好序的数列了。

创建一个函数,接受参数为一个列表,为需要排序的一系列正整数,
返回排序后的数字列表。
代码:

class Queue:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def enqueue(self, item):
        self.items.insert(0, item)

    def dequeue(self):
        return self.items.pop()

    def size(self):
        return len(self.items)


def radix_sort(s) -> list:
    # 请在此编写你的代码(可删除pass语句)
    main = Queue()
    for n in s:
        main.enqueue(n)  # 全部入队main队列

    nums = [Queue() for i in range(10)]  # 准备十个队列

    d = len(str(max(s)))  # 最大数的位数
    dstr = "%%0%dd" % d

    for i in range(-1, -d - 1, -1):  # 数字放入对应栈
        while not main.isEmpty():
            n = main.dequeue()     
            dn = (dstr % n)[i]
            nums[int(dn)].enqueue(n)
        for k in range(10):  # 从10个队列集中到main队列
            while not nums[k].isEmpty():
                main.enqueue(nums[k].dequeue())
    result = []
    while not main.isEmpty():
        result.append(main.dequeue())
    return result
    # 代码结束

结果检验:
输入:

# 调用检验
print("======== 2-radix_sort ========")
print(radix_sort([1, 2, 4, 3, 5]))
print(radix_sort([8, 91, 34, 22, 65, 30, 4, 55, 18]))

输出:

======== 2-radix_sort ========
[1, 2, 3, 4, 5]
[4, 8, 18, 22, 30, 34, 55, 65, 91]

三.HTML标记匹配

问题:
实现扩展括号匹配算法,用来检查HTML文档的标记是否匹配。
HTML标记应该成对、嵌套出现,
开标记是这种形式,闭标记是这种形式。

创建一个函数,接受参数为一个字符串,为一个HTML文档中的内容,返回True或False,表示该字符串中的标记是否匹配。
输入样例1:

<html> <head> <title> Example </title> </head> <body> <h1>Hello, world</h1> </body> </html>

输出样例1:

True

思路:
先分离出<>内需要匹配的内容,依次检查是否匹配
代码:

def HTMLMatch(s) -> bool:
    from pythonds.basic.stack import Stack
    import re

    st = Stack()

    def subString2(s):  # 获得<>内的tag内容
        rule = r'<(.*?)>'
        slotList = re.findall(rule, s)
        return slotList

    lst = subString2(s)  # 分离出需要匹配的<>中的内容

    pipei = True         # 初始值True
    if re.search('/\w+', lst[0]) != None:   # 首个tag不含/
        pipei = False
    else:
        for token in lst:
            if re.search('/\w+', token) == None:      # 不含/的tag入栈
                st.push(token)
            else:                   # 发现含/的tag时,检查与栈首的tag是否匹配,若匹配则删去栈首tag
                if token[1:] != st.peek():
                    pipei = False
                    break
                else:
                    st.pop()
                    continue

        if st.size() != 0:
            pipei = False
    return pipei

结果检验:
输入:

print("======== 3-HTMLMatch ========")
print(
    HTMLMatch(
        "<html> <head> <title>Example</title> </head> <body> <h1>Hello, world</h1> </body> </html>"
    ))
print(
    HTMLMatch(
        "<html> <head> <title> Test </title> </head> <body> <p>It's just a test.</p> <p>And this is for False.<p> </body> </html>"
    ))

输出:

======== 3-HTMLMatch ========
True
False

四.用链表实现栈和队列

问题:
用链表实现ADT Stack与ADT Queue的所有接口
栈Stack 有“先进后出”的特性
队列Queue 有“先进后出的特性”
代码:
先定义节点Node类:

class Node:
    def __init__(self, initldata):
        self.data = initldata
        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

实现Stack:

class LinkStack():

    def __init__(self):
        self.head = None  # 栈顶 head
        self.length = 0

    def isEmpty(self):
        return self.head is None

    def size(self):
        return self.length

    def peek(self):
        return self.head.getData()

    def push(self, item):  # 入栈
        top = Node(item)  # 入栈数引入一个节点
        top.setNext = (self.head)  # 该节点指向head
        self.head = top
        self.length += 1

    def pop(self):  # 出栈
        top_item = self.head.getData()
        self.head = self.head.getNext()
        self.length -= 1
        return top_item

实现队列Queue:

class LinkQueue():
    # 请在此编写你的代码(可删除pass语句)
    def __init__(self):
        self.head = None  # 队首
        self.tail = None  # 队尾
        self.length = 0

    def isEmpty(self):
        return self.head is None

    def size(self):
        return self.length

    def enqueue(self, item):
        tail = Node(item)
        if self.head is None:
            self.head = self.tail = tail  # 第一个入队的情况
        else:  # 其他情况:队尾指向item,然后item成为新队尾
            self.tail.setNext(tail)
            self.tail = self.tail.getNext()
        self.length += 1

    def dequeue(self):
        top_item = self.head.getData()  # 待出队数top_item为队首
        if self.head == self.tail:
            self.head=self.tail=None   # 队列中只有一项的情况
        else:
            self.head=self.head.getNext()   # head 变为原head的后一项
        self.length-=1
        return top_item

结果检验:
输入:

# 检验
print("======== 4-Link Stack & Link Queue ========")
s = LinkStack()
q = LinkQueue()
for i in range(10):
    s.push(i)
    q.enqueue(i)
print(s.peek(), q.dequeue())  # 9 0
print(s.pop(), q.size())  # 9 9
while not s.isEmpty():
    s.pop()
print(s.size(), q.isEmpty())  # 0 False

输出:

======== 4-Link Stack & Link Queue ========
9 0
9 9
9 False

五.实现双链无序表

问题:
实现双向链表版本的UnorderedList,接口同ADT UnorderedList
包含如下方法:isEmpty, add, search, size, remove, append,index,pop,insert, len, getitem
用于列表字符串表示的__str__方法 (注:__str__里不要使用str(), 用repr()代替
用于切片的__getitem__方法
在节点Node中增加prev变量,引用前一个节点 在UnorderedList中增加tail变量与getTail方法,引用列表中最后一个节点
选做:DoublyLinkedList(iterable) -> new DoublyLinkedList initialized from iterable’s items
选做:eq, iter

个人理解是能够实现我们通常所用列表的基本功能

代码:
这个问题需要用到二叉链表,先定义有两个指向的节点:

class Node:
    def __init__(self, initldata):
        self.data = initldata
        self.next = None
        self.prev = None

    def getData(self):
        return self.data

    def getNext(self):
        return self.next

    def getPrev(self):
        return self.prev

    def setData(self, newdata):
        self.data = newdata

    def setNext(self, newnext):
        self.next = newnext

    def setPrev(self, newprev):
        self.prev = newprev

先实现判断是否为空isEmpty,返回大小size

class DoublyLinkedList():
    def __init__(self, it=None):
        self.head = None
        self.tail = None
        self.length = 0
        if it is not None:  # 添加列表中的初始元素
            for d in it:
                self.append(d)

    def isEmpty(self):
        return self.head is None

    def size(self):
        return self.length

    __len__ = size

    def getTail(self):
        return self.tail

实现add,append,insert:

    def add(self, item):  # 加为第一个
        idx0 = Node(item)
        if self.head is None:
            self.head = self.tail = idx0  # 列表原本为空的情况
        else:
            self.head.setPrev(idx0)  # 前一个设为idx0
            idx0.setNext(self.head)  # idx0后一个设为head
            self.head = idx0  # 将原head更换为idx0
        self.length += 1

    def append(self, item):  # 加为最后一个
        idx_1 = Node(item)
        if self.head is None:
            self.head = self.tail = idx_1  # 空列表的情况
        else:
            self.tail.setNext(idx_1)
            idx_1.setPrev(self.tail)
            self.tail = idx_1
        self.length += 1

    def insert(self, idx, item):  # 加为第idx个
        current, n = self.head, 0
        while n < idx:
            current = current.getNext()
            n += 1
        if current is None:  # 两种情况,idx为0或idx为列表长度,即current为列表尾
            if self.head is None:
                self.add(item)
            else:
                self.append(item)
        else:  # idx在中间的情况,此时current=idx
            idx = Node(item)
            idx.setNext(current)
            idx.setPrev(current.getPrev())
            if idx.getPrev() is not None:
                idx.getPrev().setNext(idx)
            current.setPrev(idx)
        self.length += 1

实现idx和search:

    def index(self, item):
        current, n = self.head, 0
        while current is not None:
            if current.getData() == item:
                break
            current = current.getNext()
            n += 1
        else:
            return None
        return n

    def search(self, item):
        return self.index(item) is not None

实现delete,remove,pop:

    def delete(self, current):  # 删除节点current
        if self.head == current:
            self.head = current.getNext()
        if self.tail == current:
            self.tail = current.getPrev()
        if current.getPrev() is not None:
            current.getPrev().setNext(current.getNext())
        if current.getNext() is not None:
            current.getNext().setPrev(current.getPrev())
        self.length -= 1

    def remove(self, item):  # 删除元素item
        current = self.head
        while current is not None:
            if current.getData() == item:
                self.delete(current)
                break
            current = current.getNext()

    def pop(self, n=None):  # pop 功能
        if n is None:
            n = self.length - 1
        current, i = self.head, 0
        while i < n:
            current = current.getNext()
            i += 1
        dat = current.getData()
        self.delete(current)
        return dat

选做:

    def __str__(self):
        tlst = []
        current = self.head
        while current is not None:
            tlst.append(current.getData())
            current = current.getNext()
        return str(tlst)

    __repr__ = __str__

    def __getitem__(self, key):
        if isinstance(key, int):
            current, i = self.head, 0
            while i < key:
                current = current.getNext()
                i += 1
            if current is not None:
                return current.getData()
            else:
                raise StopIteration
        elif isinstance(key, slice):
            start = 0 if key.start is None else key.start
            stop = self.length if key.stop is None else key.stop
            step = 1 if key.step is None else key.step  # 默认参数
            current, i = self.head, 0
            while i < start:  # 定位到start
                current = current.getNext()
                i += 1
            dcopy = DoublyLinkedList()
            while i < stop:  # 依次输出
                dcopy.append(current.getData())
                s = step
                while current is not None and s > 0:
                    current = current.getNext()
                    s -= 1
                i += step
            return dcopy

    def __eq__(self, other):
        if other is None or not isinstance(other, DoublyLinkedList):
            return False
        if len(self) != len(other):
            return False
        for s, o in zip(self, other):
            if s != o:
                return False
        else:
            return True

结果检验:
输入:

# 检验
print("======== 5-DoublyLinkedList ========")
mylist = DoublyLinkedList()
for i in range(0, 20, 2):
    mylist.append(i)
mylist.add(3)
mylist.remove(6)
print(mylist.getTail().getPrev().getData())  # 16
print(mylist.isEmpty())  # False
print(mylist.search(5))  # False
print(mylist.size())  # 10
print(mylist.index(2))  # 2
print(mylist.pop())  # 18
print(mylist.pop(2))  # 2
print(mylist)  # [3, 0, 4, 8, 10, 12, 14, 16]
mylist.insert(3, "10")
print(len(mylist))  # 9
print(mylist[4])  # 8
print(mylist[3:8:2])  # ['10', 10, 14]

输出:

======== 5-DoublyLinkedList ========
16
False
False
10
2
18
2
[3, 0, 4, 8, 10, 12, 14, 16]
9
8
['10', 10, 14]

文章内容参考 python数据结构与算法课程 陈斌

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值