3.Python数据结构与算法分析课后习题(第二版)__chapter3

chpater3_answer


参考链接:
https://zhuanlan.zhihu.com/p/130436689 link

一、讨论题

略略略

二、编程练习

1.修改从中序到后序的转换算法,使其能处理异常情况。

from chapter3.stack import Stack
import string


def infixToPostfix(infixexpr):
    prec = {}
    prec["("] = 1
    prec["+"] = 2
    prec["-"] = 2
    prec["*"] = 3
    prec["/"] = 3
    opstack = Stack()
    postfixList = []
    count = 0

    tokenList = infixexpr.split()
    lenth = len(tokenList)

    for i in range(lenth):
        if tokenList[i] in string.ascii_uppercase and (tokenList[i+1] in string.ascii_uppercase or tokenList[i-1] == ")" or tokenList[i+1] == "("):
            return "Input Error"
        if tokenList[i] in "+-*/" and (tokenList[i+1] in "+-*/)" or tokenList[i-1] in "+-*/(" ):
            return "Input Error"
        if i+1 < lenth and tokenList[i] == ')' and tokenList[i+1] == "(":
            return "Input Error"

    for token in tokenList:
        if token in string.ascii_uppercase:
            postfixList.append(token)
        elif token == '(':
            count += 1
            opstack.push(token)
        elif token == ')':
            count -= 1
            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)
    if count != 0:
        return "Input Error"

    while not opstack.isEmpty():
        postfixList.append(opstack.pop())

    return " ".join(postfixList)

if __name__ == '__main__':
    print(infixToPostfix("( A + - V )"))
    print(infixToPostfix("( A + B )"))

2.修改计算后序表达式的算法,使其能处理异常情况。

from chapter3.stack import Stack

def postfixEval(postfixExpr):
    numstack = Stack()
    tokenList = postfixExpr.split()
    try:
        for token in tokenList:
            if token in "0123456789":
                numstack.push(int(token))
            else:
                num1 = numstack.pop()
                num2 = numstack.pop()
                result = doMath(token, num1, num2)
                numstack.push(result)

        if numstack.size() == 1:
            return numstack.pop()
        else:
            return "Input Error"
    except:
        return "Input Error"

def doMath(op, n1, n2):

    if op == "*":
        return n1 * n2
    elif op == "/":
        return n1 / n2
    elif op == "+":
        return n1 + n2
    else:
        return n1 - n2

if __name__ == '__main__':

    print(postfixEval("4  * 6"))

3.结合从中序到后序的转换算法以及计算后序表达式的算法,实现直接的中序计算。在计算时,应该使用两个栈从左往右处理中序表达式标记。一个栈用于保存运算符,另一个用于保存操作数。

from chapter3.stack import Stack

def infixEval(infixExpr):
    opstack = Stack()
    numstack = Stack()

    tokenList = infixExpr.split()

    for token in tokenList:
        if token in "+-*/()":
            if token == ")":
                while opstack.peek() != '(':
                    num2 = numstack.pop()
                    num1 = numstack.pop()
                    op = opstack.pop()
                    res = doMath(op, num1, num2)
                    numstack.push(res)
                opstack.pop()
            else:
                opstack.push(token)
        else:
            numstack.push(float(token))

    return numstack.pop()

def doMath(op, n1, n2):

    if op == "*":
        return n1 * n2
    elif op == "/":
        return n1 / n2
    elif op == "+":
        return n1 + n2
    else:
        return n1 - n2

if __name__ == '__main__':
    print(infixEval("( 2 + 13.1 )"))

4.将在练习3中实现的算法做成一个计算器。

效果如图:
在这里插入图片描述
主要加了俩括号,参考链接:https://zhuanlan.zhihu.com/p/130436689 link

import math
import tkinter
from chapter3.stack import Stack

root = tkinter.Tk()
root.resizable(width=False, height=False)
'''hypeparameter'''
# 是否按下了运算符
IS_CALC = False
# 存储数字
STORAGE = []
Expression = ''
# 显示框最多显示多少个字符
MAXSHOWLEN = 18
# 当前显示的数字
CurrentShow = tkinter.StringVar()
CurrentShow.set('0')

'''按下小数点'''
def pressDP():
	global IS_CALC
	if IS_CALC:
		CurrentShow.set('0')
		IS_CALC = False
	if len(CurrentShow.get().split('.')) == 1:
		if len(CurrentShow.get()) < MAXSHOWLEN:
			CurrentShow.set(CurrentShow.get() + '.')

'''清零'''
def clearAll():
	global STORAGE
	global IS_CALC
	STORAGE.clear()
	IS_CALC = False
	CurrentShow.set('0')

'''清除当前显示框内所有数字'''
def clearCurrent():
	CurrentShow.set('0')

'''删除显示框内最后一个数字'''
def delOne():
	global IS_CALC
	if IS_CALC:
		CurrentShow.set('0')
		IS_CALC = False
	if CurrentShow.get() != '0':
		if len(CurrentShow.get()) > 1:
			CurrentShow.set(CurrentShow.get()[:-1])
		else:
			CurrentShow.set('0')

'''计算答案修正'''
def modifyResult(result):
	result = str(result)
	if len(result) > MAXSHOWLEN:
		if len(result.split('.')[0]) > MAXSHOWLEN:
			result = 'Overflow'
		else:
			# 直接舍去不考虑四舍五入问题
			result = result[:MAXSHOWLEN]
	return result

'''按下运算符'''
def pressOperator(operator):
	global STORAGE
	global IS_CALC
	if operator == '+/-':
		if CurrentShow.get().startswith('-'):
			CurrentShow.set(CurrentShow.get()[1:])
		else:
			CurrentShow.set('-'+CurrentShow.get())
	elif operator == '1/x':
		try:
			result = 1 / float(CurrentShow.get())
		except:
			result = 'illegal operation'
		result = modifyResult(result)
		CurrentShow.set(result)
		IS_CALC = True
	elif operator == 'sqrt':
		try:
			result = math.sqrt(float(CurrentShow.get()))
		except:
			result = 'illegal operation'
		result = modifyResult(result)
		CurrentShow.set(result)
		IS_CALC = True
	elif operator == 'MC':
		STORAGE.clear()
	elif operator == 'MR':
		if IS_CALC:
			CurrentShow.set('0')
		STORAGE.append(CurrentShow.get())
		expression = ''.join(STORAGE)
		try:
			result = eval(expression)
		except:
			result = 'illegal operation'
		result = modifyResult(result)
		CurrentShow.set(result)
		IS_CALC = True
	elif operator == 'MS':
		STORAGE.clear()
		STORAGE.append(CurrentShow.get())
	elif operator == 'M+':
		STORAGE.append(CurrentShow.get())
	elif operator == 'M-':
		if CurrentShow.get().startswith('-'):
			STORAGE.append(CurrentShow.get())
		else:
			STORAGE.append('-' + CurrentShow.get())

def pressExpression(operator):
    global Expression
    print(list)
    if operator != '=':

        Expression += operator
    else:
        expression = ' '.join(Expression)
        result = infixEval(expression)
        CurrentShow.set(result)

def infixEval(infixExpr):
    opstack = Stack()
    numstack = Stack()

    tokenList = infixExpr.split()

    for token in tokenList:
        if token in "+-*/()":
            if token == ")":
                while opstack.peek() != '(':
                    num2 = numstack.pop()
                    num1 = numstack.pop()
                    op = opstack.pop()
                    res = doMath(op, num1, num2)
                    numstack.push(res)
                opstack.pop()
            else:
                opstack.push(token)
        else:
            numstack.push(float(token))

    return numstack.pop()

def doMath(op, n1, n2):

    if op == "*":
        return n1 * n2
    elif op == "/":
        return n1 / n2
    elif op == "+":
        return n1 + n2
    else:
        return n1 - n2

'''Demo'''
def Demo():
	root.minsize(320, 420)
	root.title('Calculator')
	# 布局
	# --文本框
	label = tkinter.Label(root, textvariable=CurrentShow, bg='black', anchor='e', bd=5, fg='white', font=('楷体', 20))
	label.place(x=20, y=50, width=280, height=50)
	# --第一行
	# ----Memory clear
	button1_1 = tkinter.Button(text='MC', bg='#666', bd=2, command=lambda:pressOperator('MC'))
	button1_1.place(x=20, y=110, width=50, height=35)
	# ----Memory read
	button1_2 = tkinter.Button(text='MR', bg='#666', bd=2, command=lambda:pressOperator('MR'))
	button1_2.place(x=77.5, y=110, width=50, height=35)
	# ----Memory save
	button1_3 = tkinter.Button(text='MS', bg='#666', bd=2, command=lambda:pressOperator('MS'))
	button1_3.place(x=135, y=110, width=50, height=35)
	# ----Memory +
	button1_4 = tkinter.Button(text='M+', bg='#666', bd=2, command=lambda:pressOperator('M+'))
	button1_4.place(x=192.5, y=110, width=50, height=35)
	# ----Memory -
	button1_5 = tkinter.Button(text='M-', bg='#666', bd=2, command=lambda:pressOperator('M-'))
	button1_5.place(x=250, y=110, width=50, height=35)
	# --第二行
	# ----删除单个数字
	button2_1 = tkinter.Button(text='del', bg='#666', bd=2, command=lambda:delOne())
	button2_1.place(x=20, y=155, width=50, height=35)
	# ----清除当前显示框内所有数字
	button2_2 = tkinter.Button(text='CE', bg='#666', bd=2, command=lambda:clearCurrent())
	button2_2.place(x=77.5, y=155, width=50, height=35)
	# ----清零(相当于重启)
	button2_3 = tkinter.Button(text='C', bg='#666', bd=2, command=lambda:clearAll())
	button2_3.place(x=135, y=155, width=50, height=35)
	# ----取反
	button2_4 = tkinter.Button(text='+/-', bg='#666', bd=2, command=lambda:pressOperator('+/-'))
	button2_4.place(x=192.5, y=155, width=50, height=35)
	# ----开根号
	button2_5 = tkinter.Button(text='sqrt', bg='#666', bd=2, command=lambda:pressOperator('sqrt'))
	button2_5.place(x=250, y=155, width=50, height=35)
	# --第三行
	# ----7
	button3_1 = tkinter.Button(text='7', bg='#bbbbbb', bd=2, command=lambda:pressExpression('7'))
	button3_1.place(x=20, y=200, width=50, height=35)
	# ----8
	button3_2 = tkinter.Button(text='8', bg='#bbbbbb', bd=2, command=lambda:pressExpression('8'))
	button3_2.place(x=77.5, y=200, width=50, height=35)
	# ----9
	button3_3 = tkinter.Button(text='9', bg='#bbbbbb', bd=2, command=lambda:pressExpression('9'))
	button3_3.place(x=135, y=200, width=50, height=35)
	# ----除
	button3_4 = tkinter.Button(text='/', bg='#708069', bd=2, command=lambda:pressExpression('/'))
	button3_4.place(x=192.5, y=200, width=50, height=35)
	# ----取余
	button3_5 = tkinter.Button(text=')', bg='#708069', bd=2, command=lambda:pressExpression(')'))
	button3_5.place(x=250, y=200, width=50, height=35)
	# --第四行
	# ----4
	button4_1 = tkinter.Button(text='4', bg='#bbbbbb', bd=2, command=lambda:pressExpression('4'))
	button4_1.place(x=20, y=245, width=50, height=35)
	# ----5
	button4_2 = tkinter.Button(text='5', bg='#bbbbbb', bd=2, command=lambda:pressExpression('5'))
	button4_2.place(x=77.5, y=245, width=50, height=35)
	# ----6
	button4_3 = tkinter.Button(text='6', bg='#bbbbbb', bd=2, command=lambda:pressExpression('6'))
	button4_3.place(x=135, y=245, width=50, height=35)
	# ----乘
	button4_4 = tkinter.Button(text='*', bg='#708069', bd=2, command=lambda:pressExpression('*'))
	button4_4.place(x=192.5, y=245, width=50, height=35)
	# ----取导数
	button4_5 = tkinter.Button(text='(', bg='#708069', bd=2, command=lambda:pressExpression('('))
	button4_5.place(x=250, y=245, width=50, height=35)
	# --第五行
	# ----3
	button5_1 = tkinter.Button(text='3', bg='#bbbbbb', bd=2, command=lambda:pressExpression('3'))
	button5_1.place(x=20, y=290, width=50, height=35)
	# ----2
	button5_2 = tkinter.Button(text='2', bg='#bbbbbb', bd=2, command=lambda:pressExpression('2'))
	button5_2.place(x=77.5, y=290, width=50, height=35)
	# ----1
	button5_3 = tkinter.Button(text='1', bg='#bbbbbb', bd=2, command=lambda:pressExpression('1'))
	button5_3.place(x=135, y=290, width=50, height=35)
	# ----减
	button5_4 = tkinter.Button(text='-', bg='#708069', bd=2, command=lambda:pressExpression('-'))
	button5_4.place(x=192.5, y=290, width=50, height=35)
	# ----等于
	button5_5 = tkinter.Button(text='=', bg='#708069', bd=2, command=lambda:pressExpression('='))
	button5_5.place(x=250, y=290, width=50, height=80)
	# --第六行
	# ----0
	button6_1 = tkinter.Button(text='0', bg='#bbbbbb', bd=2, command=lambda:pressExpression('0'))
	button6_1.place(x=20, y=335, width=107.5, height=35)
	# ----小数点
	button6_2 = tkinter.Button(text='.', bg='#bbbbbb', bd=2, command=lambda:pressDP())
	button6_2.place(x=135, y=335, width=50, height=35)
	# ----加
	button6_3 = tkinter.Button(text='+', bg='#708069', bd=2, command=lambda:pressExpression('+'))
	button6_3.place(x=192.5, y=335, width=50, height=35)
	root.mainloop()

if __name__ == '__main__':
	Demo()

5.使用列表实现队列抽象数据类型,将列表的后端作为队列的尾部。

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

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

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

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

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

6.设计和实现一个实验,对比两种队列实现的性能。能从该实验学到什么?

以队列的入队操作为例,第一个队列以列表头部做队头,第二个队列以列表尾部做队头。

import timeit
import matplotlib.pyplot as plt

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

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

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

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

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

class Queue2:
    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)

lenx = []
q1y = []
q2y = []
color = ['c', 'b', 'g', 'r', 'm', 'y', 'k', 'w']

if __name__ == '__main__':
    Q1 = Queue1()
    Q2 = Queue2()

    for i in range(100, 200000, 5000):
        t1 = timeit.Timer("Q1.enqueue(%d)" % i,"from __main__ import Q1")
        t2 = timeit.Timer("Q2.enqueue(%d)" % i, "from __main__ import Q2")
        x = list(range(i))
        Q1.items = x
        q1_time = t1.timeit(number=1)
        x = list(range(i))
        Q2.items = x
        q2_time = t2.timeit(number=1)
        print("%d, %15.8f, %15.8f" % (i, q1_time, q2_time))

        lenx.append(i)
        q1y.append(q1_time)
        q2y.append(q2_time)
        ax = plt.gca()
        # 去掉边框
        ax.spines['top'].set_color('none')
        ax.spines['right'].set_color('none')
        # 移位置 设为原点相交
        ax.xaxis.set_ticks_position('bottom')
        ax.spines['bottom'].set_position(('data', 0))
        ax.yaxis.set_ticks_position('left')
        ax.spines['left'].set_position(('data', 0))
        plt.ylim(0, 0.0003)
        q1dot = plt.scatter(lenx, q1y, c=color[3], edgecolors='r', label='Q1')
        q2dot = plt.scatter(lenx, q2y, c=color[1], edgecolors='b', marker='^', label='Q2')
        plt.xlabel('lenth(list&dict)')
        plt.ylabel('time(/s)')
        plt.title('Q1&Q2_enqueue()_analysis')
        plt.legend()
        plt.show()

结果如图:
请添加图片描述
由实验知

  1. 以列表头部做队头的队列入队操作的时间复杂度为常数阶:O( 1 1 1)
  2. 以列表尾部做队头的队列入队操作的时间复杂度为线性阶:O( n n n)

7.实现一个队列,使其添加操作和移除操作的平均时间复杂度为O( 1 1 1)。这意味着在大多数情况下,两个操作的时间复杂度都是O( 1 1 1),仅在一种特殊情况下,移除操作为O( n n n)。

【存疑】
  考虑输入受限的双端队列,即允许在一端进行添加和删除,另一端只允许删除。

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

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

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

    def removeFront(self):
        return self.items.pop(0)

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

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

if __name__ == '__main__':
    deq = Dequeue()
    deq.addRear(2)
    print(deq.items)

8.考虑现实生活中的一个情景。完整地定义问题,并且设计一个模拟来解决它。

  以排队等待洗车——求顾客平均等待时间为例:假设在给定的一小时内,这家洗车店总有十个顾客,并且每人都洗一次车。那么每小时平均有10个洗车任务,相当于每 60/10 = 6分钟(360秒)有一个任务,即在任意一秒,创建一个洗车任务的概率为1/360,通过1~360的随机数模拟每秒内产生洗车任务的概率。若随机数=360,则认为创建洗车任务。
  创建三个类:WashingCar、Task、Queue分别模拟洗车店、洗车任务、队列。假设车的类型分三类:小型车、中型车、大型车,并规定若洗车店洗小车的速度为 N mins洗一辆,则洗一辆中型车需 2N mins,大型车 3N mins。车类型通过1~3的随机数来模拟。

import random
from chapter3.queue import Queue

class Task:
    def __init__(self, time):
        self.timestamp = time
        self.carclass = random.randrange(1, 4)

    def getStamp(self):
        return self.timestamp

    def getCarclass(self):
        return self.carclass

    def waitTime(self, currenttime):
        return currenttime - self.timestamp

class WashingCar:
    def __init__(self, ppm):
        self.carrate = ppm
        self.currentTask = None
        self.timeRemaining = 0

    def tick(self):
        if self.currentTask != None:
            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.getCarclass()*60*self.carrate

def simulation(numseconds, minutesPercar):

    washing = WashingCar(minutesPercar)
    carsQueue = Queue()
    waitingtimes = []

    for currentSecond in range(numseconds):
        if newwashingTask():
            task = Task(currentSecond)
            carsQueue.enqueue(task)

        if (not washing.busy()) and (not carsQueue.isEmpty()):
            nexttask = carsQueue.dequeue()
            waitingtimes.append(nexttask.waitTime(currentSecond))
            washing.startNext(nexttask)
        washing.tick()


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

def newwashingTask():
    num = random.randrange(1, 361)
    if num == 360:
        return True
    else:
        return False

if __name__ == '__main__':

    for i in range(10):
        simulation(3600, 5)

9. 修改传土豆模拟程序,允许随机计数,从而使每一轮的结果都不可预测。

from chapter3.queue import Queue
import random

def hotPotato(namelist):
    q = Queue()
    for name in namelist:
        q.enqueue(name)

    while q.size() > 1:
        num = n = random.randrange(1, 101)
        for i in range(num):
            q.enqueue(q.dequeue())
        q.dequeue()

    return q.dequeue()

if __name__ == '__main__':

    namelist =['Bill', 'David', 'Susan', 'Jane', 'Kent', 'Brad']
    for i in range(10):
        print("第%d次出局人: %s" % (i+1 , hotPotato(namelist)))

10.实现一个基数排序器。

  十进制数的基数排序利用1个主桶和10个数位桶。每个桶就像一个队列,并且根据数字到达的先后顺序来维持其中的值。该算法首先将所有的数都放在主桶中,然后按照数值中的每一个数位来考察这些值。第一个值从主桶中移除并且根据在考察的数位将其放到对应的数位桶中。如果考察的是个位,那么534将被放在4号数位桶中,667则放在7号数位桶中。一旦所有的值都被放在了相应的数位桶中,便依次从0号到9号数位桶中将值放回主桶。重复整个过程到数字的十位、百位等。在最后一个数位被处理完之后,主桶里面就是排好序的值。

  网上找了一个过程图(已包浆🤣)
  参考链接:https://blog.csdn.net/double_happiness/article/details/72452243
link
在这里插入图片描述
咱们这是用队列来表示题目的桶:

from chapter3.queue import Queue

def cardinalitysorted(alist):
    
    result = []
    masterq = Queue()
    numslist = []
    maxnumlen = 0
    for i in range(10):
        numslist.append(Queue())

    for i in range(len(alist)):
        maxnumlen = max(maxnumlen, len(str(alist[i])))
        masterq.enqueue(alist[i])

    for i in range(maxnumlen):
        while not masterq.isEmpty():
            cur = masterq.dequeue()
            radix = int(cur / (10 ** i) % 10)
            numslist[radix].enqueue(cur)
        for j in range(10):
            while not numslist[j].isEmpty():
                masterq.enqueue(numslist[j].dequeue())

    for i in range(len(alist)):
        result.append(masterq.dequeue())

    return result


if __name__ == '__main__':
    ml = [54, 678, 3215, 57, 4123, 3, 3535, 90]
    print(cardinalitysorted(ml))

11.HTML 中也存在括号匹配问题。标签有开始和结束两种形式,并且需要互相匹配才能正确描述网页内容。写一个程序来检查HTML文档中的标签是否正确匹配。

下面是简单的html文档,用于展示标签的匹配和嵌套。

<html>
    <head>
        <title>
            example
        </title>
    </head>

    <body>
        <h1>hello world</h1>
    </body>
</html>
from chapter3.stack import Stack

def parCheckerHtml(symbolString):
    s = Stack()
    matched = True
    index = 0
    while index < len(symbolString) and matched:
        str = symbolString[index]
        if str in ["<html>", "<head>", "<title>", "<body>","<h1>"]:
            s.push(str)
        if str in ["</html>", "</head>", "</title>", "</body>","</h1>"]:
            if s.isEmpty():
                matched = False
            else:
                top = s.pop()
                if not matches(top, str):
                    matched = False

        index += 1

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

def matches(left, right):
    lefts = ["<html>", "<head>", "<title>", "<body>","<h1>"]
    rights = ["</html>", "</head>", "</title>", "</body>","</h1>"]
    return lefts.index(left) == rights.index(right)

if __name__ == '__main__':

    file_path = "test.html"
    string = open(file_path).read().split()
    print(parCheckerHtml(string))

12.扩展代码清单3-15 中的回文检测器,使其可以处理包含空格的回文。如果忽略其中的空格,那么I PREFER PI 就是回文。

from chapter3.dequeue import Dequeue

def palchecker(aString):
    chardeque = Dequeue()
    for ch in aString:
        if ch == ' ':
            continue
        chardeque.addRear(ch)

    matched = True
    while matched and chardeque.size() > 1:
        left = chardeque.removeRear()
        right = chardeque.removeFront()
        if left != right:
            matched = False
    return matched

if __name__ == '__main__':

    str = "I PREFER PI"
    print(str)
    print(palchecker(str))

13. 本章通过计算列表中节点的个数来实现length 方法。另一种做法是将节点个数作为额外的信息保存在列表头中。请修改UnorderedList 类的实现,使其包含节点个数信息,并且重新实现length 方法。

&

14. 实现remove 方法,使其能正确处理待移除元素不在列表中的情况。

class unorderList:
    def __init__(self):
        self.head = None
        self.lenth = 0

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

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

    def length(self):
        return self.lenth

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

    def remove(self, item):
        try:
            q = self.head
            pre = None
            found = False
            while not found:
                if q.getData() == item:
                    found = True
                else:
                    pre = q
                    q = q.getNext()
            if pre == None:
                self.head = q.getNext()
            else:
                pre.setNext(q.getNext())
            self.lenth -= 1
        except:
            print("待移除的元素不在列表中")

15. 修改列表类,使其能支持重复元素。这一改动会影响到哪些方法?

&

16. 实现UnorderedList类的__str__方法。列表适合用什么样的字符串表示?

&

17. 实现__str__方法,使列表按照Python 的方式来显示(使用方括号)。

&

18. 实现无序列表抽象数据类型剩余的方法:append、index、pop 和insert。

&

19. 实现UnorderedList 类的slice 方法。该方法接受start和stop两个参数, 并且返回一个从start位置开始,到stop位置结束的新列表(但不包含stop位置上的元素)。

from chapter3.node import Node

class unorderList:
    def __init__(self):
        self.head = None
        self.lenth = 0

    def __str__(self):
        string = ''
        p = self.head
        while p != None:
            if p.getNext() != None:
                string += str(p.getData()) + ','
            else:
                string += str(p.getData())
            p = p.getNext()
        # return string
        return '[' +string+ ']'

    def append(self, alist):
        p = self.head
        while p.getNext() != None:
            p = p.getNext()
        p.setNext(alist.head)

    def index(self, item):
        p = self.head
        idx = 0
        while p != None:
            if str(p.getData()) == str(item):
                break
            p = p.getNext()
            idx += 1
        return idx

    def pop(self):
        p = self.head
        pre = None
        if p == None:
            return "空列表无法pop()"
        while p.getNext() != None:
            pre = p
            p = p.getNext()
        if pre != None:
            pre.setNext(None)
            self.lenth -= 1
            return p.getData()
        else:
            self.head = None
            self.lenth = 0
            return p.getData()

    def insert(self, idx, item):
        try:
            p = self.head
            pre = self.head
            temp = Node(item)
            if idx == 0:
                temp.setNext(self.head)
                self.head = temp
                self.lenth += 1
                return self
            elif idx < 0:
                return "Input Error"
            else:
                for i in range(idx):
                    pre = p
                    p = p.getNext()

            pre.setNext(temp)
            temp.setNext(p)
            self.lenth += 1
            return self
        except:
            print("Input Error")

    def slice(self, start, stop):

        p = self.head
        i ,j= 0, start
        templist = unorderList()
        while i < start:
            p = p.getNext()
            i += 1
        templist.head = p
        pre = templist.head
        templist.lenth += 1
        while j < stop and p.getNext()!=None:
            pre = p
            p = p.getNext()
            j += 1
        pre.setNext(None)
        return templist

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

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

    def length(self):
        return self.lenth

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

    def remove(self, item):
        try:
            q = self.head
            pre = None
            found = False
            while not found:
                if q.getData() == item:
                    found = True
                else:
                    pre = q
                    q = q.getNext()
            if pre == None:
                self.head = q.getNext()
            else:
                pre.setNext(q.getNext())
            self.lenth -= 1
        except:
            print("待移除的元素不在列表中")

if __name__ == '__main__':
    mylist = unorderList()

    mylist.add(12)
    mylist.add(12)
    mylist.add(456)
    mylist.add(23)
    mylist.add(157)
    mylist.add(13)
    mylist.add(17)
    list2 = unorderList()
    list2.add(1)
    list2.add(2)
    mylist.append(list2)
    print(mylist)
    print(mylist.index('23'))
    p = mylist.head
    print(mylist.pop())
    print(mylist)
    mylist1 = mylist.insert(0, 66)
    print(mylist1)
    mylist2 = mylist.slice(3,4)

20. 实现有序列表抽象数据类型剩余的方法。

from chapter3.node import Node

class orderList:
    def __init__(self):
        self.head = None
        self.lenth = 0

    def __str__(self):
        string = ''
        p = self.head
        while p != None:
            if p.getNext() != None:
                string += str(p.getData()) + ','
            else:
                string += str(p.getData())
            p = p.getNext()
        # return string
        return '[' +string+ ']'

    def append(self, alist):

        newlist = self

        q = alist.head
        print(q.getData())
        while q != None:
            p = newlist.head
            pre = p
            data = q.getData()
            temp = Node(data)
            if data < p.getData():
                temp.setNext(p)
                newlist.head = temp
                newlist.lenth += 1
                q = q.getNext()
            else:
                while p != None :
                    if data < p.getData():
                        break
                    pre = p
                    p = p.getNext()
                q = q.getNext()
                pre.setNext(temp)
                temp.setNext(p)
                newlist.lenth += 1
        return newlist

    def index(self, item):
        p = self.head
        idx = 0
        while p != None:
            if str(p.getData()) == str(item):
                break
            p = p.getNext()
            idx += 1
        return idx

    def pop(self):
        p = self.head
        pre = None
        if p == None:
            return "空列表无法pop()"
        while p.getNext() != None:
            pre = p
            p = p.getNext()
        if pre != None:
            pre.setNext(None)
            self.lenth -= 1
            return p.getData()
        else:
            self.head = None
            self.lenth = 0
            return p.getData()

    def insert(self, idx, item):
        try:
            p = self.head
            pre = self.head
            temp = Node(item)
            if idx == 0:
                temp.setNext(self.head)
                self.head = temp
                self.lenth += 1
                return self
            elif idx < 0:
                return "Input Error"
            else:
                for i in range(idx):
                    if item < p.getData():
                        return "Input Error"
                    print("aaaa",i)
                    pre = p
                    p = p.getNext()
            if item > p.getData():
                return "Input Error"

            pre.setNext(temp)
            temp.setNext(p)
            self.lenth += 1
            return self
        except:
            print("Input Error")
    def slice(self, start, stop):

        p = self.head
        i ,j= 0, start+1
        templist = orderList()
        while i <= start:
            p = p.getNext()
            i += 1
        templist.head = p
        pre = templist.head
        templist.lenth += 1
        while j <= stop and p:
            pre = p
            p = p.getNext()
            j += 1
        pre.setNext(None)
        return templist

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

    def add(self, item):
        p = self.head
        pre = None
        temp = Node(item)
        while p != None:
            if item < p.getData():
                break;
            pre = p
            p = p.getNext()

        if pre == None:
            temp.setNext(self.head)
            self.head = temp
        else:
            temp.setNext(p)
            pre.setNext(temp)

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

        return count

    def search(self, item):
        q = self.head
        found = False
        while not found and q != None:
            if q.getData() == item:
                found = True
            elif q.getData() > item:
                break
            q = q.getNext()
        return found

    def remove(self, item):
        q = self.head
        pre = None
        found = False
        while not found:
            if q.getData() == item:
                found = True
            else:
                pre = q
                q = q.getNext()

        if pre == None:
            self.head = q.getNext()
        else:
            pre.setNext(q.getNext())

if __name__ == '__main__':
    mylist = orderList()

    mylist.add(9)
    mylist.add(8)
    mylist.add(7)
    mylist.add(6)
    mylist.add(5)
    mylist.add(2)
    list2 = orderList()
    list2.add(4)
    list2.add(3)
    list2.add(11)
    print(mylist)
    print(list2)
    mylist.append(list2)
    print(mylist)
    print(mylist.index('5'))
    print(mylist.pop())
    print(mylist)
    print(mylist.insert(2,1))

21. 思考有序列表和无序列表的关系。能否利用继承关系来构建更高效的实现?试着实现这个继承结构。

有序列表对于无序列表只是多了一个有序属性,有序可以继承父类无序。

from chapter3_answer.t15_19 import unorderList
from chapter3.node import Node

class orderList(unorderList):
    def __init__(self):
        self.head = None
        self.lenth = 0

    def __str__(self):
        return super(orderList, self).__str__()


    def append(self, alist):

        newlist = self

        q = alist.head
        print(q.getData())
        while q != None:
            p = newlist.head
            pre = p
            data = q.getData()
            temp = Node(data)
            if data < p.getData():
                temp.setNext(p)
                newlist.head = temp
                newlist.lenth += 1
                q = q.getNext()
            else:
                while p != None :
                    if data < p.getData():
                        break
                    pre = p
                    p = p.getNext()
                q = q.getNext()
                pre.setNext(temp)
                temp.setNext(p)
                newlist.lenth += 1
        return newlist

    def index(self, item):
        return super(orderList, self).index(item)


    def pop(self):
        print("pop")
        return super(orderList, self).pop()
        #

    def insert(self, idx, item):
        try:
            p = self.head
            pre = self.head
            temp = Node(item)
            if idx == 0:
                temp.setNext(self.head)
                self.head = temp
                self.lenth += 1
                return self
            elif idx < 0:
                return "Input Error"
            else:
                for i in range(idx):
                    if item < p.getData():
                        return "Input Error"
                    pre = p
                    p = p.getNext()
            if item > p.getData():
                return "Input Error"

            pre.setNext(temp)
            temp.setNext(p)
            self.lenth += 1
            return self
        except:
            print("Input Error")

    def slice(self, start, stop):
        p = self.head
        i, j = 0, start + 1
        templist = orderList()
        while i <= start:
            p = p.getNext()
            i += 1
        templist.head = p
        pre = templist.head
        templist.lenth += 1
        while j <= stop and p:
            pre = p
            p = p.getNext()
            j += 1
        pre.setNext(None)
        return templist

    def isEmpty(self):
        return super(orderList, self).isEmpty()

    def add(self, item):
        p = self.head
        pre = None
        temp = Node(item)
        while p != None:
            if item < p.getData():
                break;
            pre = p
            p = p.getNext()

        if pre == None:
            temp.setNext(self.head)
            self.head = temp
        else:
            temp.setNext(p)
            pre.setNext(temp)

    def length(self):
        return super(orderList, self).length()

    def search(self, item):
        q = self.head
        found = False
        while not found and q != None:
            if q.getData() == item:
                found = True
            elif q.getData() > item:
                break
            q = q.getNext()
        return found

    def remove(self, item):
        q = self.head
        pre = None
        found = False
        while not found:
            if q.getData() > item:
                return "待移除的元素不在列表中"
            elif q.getData() == item:
                found = True
            else:
                pre = q
                q = q.getNext()

        if pre == None:
            self.head = q.getNext()
        else:
            pre.setNext(q.getNext())

if __name__ == '__main__':
    mylist = orderList()

    mylist.add(9)
    mylist.add(8)
    mylist.add(7)
    mylist.add(6)
    mylist.add(5)
    mylist.add(2)
    list2 = orderList()
    list2.add(4)
    list2.add(3)
    list2.add(11)
    print(mylist)
    print(list2)
    mylist.append(list2)
    print(mylist)
    print(mylist.index('5'))
    print(mylist.pop())
    print(mylist)
    print(mylist.slice(0,3))

22. 使用链表实现栈。

from chapter3_answer.t15_19 import unorderList

class Stack(unorderList):
    def __init__(self):
        self.head = None
        self.lenth = 0

    def isEmpty(self):
        return super(Stack, self).isEmpty()

    def push(self, item):
        return super(Stack, self).add(item)

    def pop(self):
        p = self.head
        if p == None:
            return "list is null"
        else:
            pre = p
            p = p.getNext()
            self.head = p
            self.lenth -= 1

        return pre.getData()

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

    def size(self):
        return self.lenth

if __name__ == '__main__':

    mylist = Stack()
    mylist.push(12)
    mylist.push(456)
    mylist.push(23)
    mylist.push(157)
    mylist.push(13)
    mylist.push(17)
    print(mylist)
    print(mylist.lenth)
    print(mylist.pop())
    print(mylist.lenth)
    print(mylist.peek())

23.使用链表实现队列。

from chapter3_answer.t15_19 import unorderList

class Queue(unorderList):
    def __init__(self):
        self.head = None
        self.lenth = 0

    def isEmpty(self):
        return super(Queue, self).isEmpty()

    def enqueue(self, item):
        return super(Queue, self).add(item)

    def dequeue(self):
        return super(Queue, self).pop()

    def size(self):
        return self.lenth

if __name__ == '__main__':
    q = Queue()
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    print(q)
    print(q.dequeue())

    print(q.size())
    q.dequeue()
    q.dequeue()
    print(q.isEmpty())

24. 使用链表实现双端队列。

from chapter3_answer.t15_19 import unorderList
from chapter3.node import Node

class Dequeue(unorderList):
    def __init__(self):
        self.head = None
        self.lenth = 0

    def isEmpty(self):
        return super(Dequeue, self).isEmpty()

    def addFront(self, item):
        p = self.head
        temp = Node(item)
        if p == None:
            return super(Dequeue, self).add(item)
        else:
            while p.getNext() != None:
                p = p.getNext()

            p.setNext(temp)
            self.lenth += 1

    def addRear(self, item):
        return super(Dequeue, self).add(item)

    def removeFront(self):
        return super(Dequeue, self).pop()

    def removeRear(self):
        p = self.head
        if p == None:
            return "list is null"
        else:
            pre = p
            p = p.getNext()
            self.head = p
            self.lenth -= 1

        return pre.getData()

    def size(self):
        return self.lenth


if __name__ == '__main__':
    deq = Dequeue()
    deq.addFront(1)
    deq.addRear(2)
    deq.addFront(7)
    deq.addFront(5)
    print(deq)
    print(deq.removeFront())
    print(deq.removeRear())
    print(deq)

25. 设计和实现一个实验,比较用链表实现的列表与Python列表的性能。

以列表的插入insert为例:

from chapter3_answer.t15_19 import unorderList
import timeit
import matplotlib.pyplot as plt

lenx = []
insert1y = []
insert2y = []
color = ['c', 'b', 'g', 'r', 'm', 'y', 'k', 'w']

if __name__ == '__main__':
    L = unorderList()

    for i in range(100, 200000, 5000):
        t1 = timeit.Timer("x.insert(0, %d)" % i, "from __main__ import random, x")
        t2 = timeit.Timer("L.insert(0, %d)" % i, "from __main__ import random, L")
        x = list(range(i))
        inserttime1 = t1.timeit(number=1)
        for m in range(i):
            L.add(m)
        inserttime2 = t2.timeit(number=1)
        print("%d, %15.6f,%15.6f" % (i, inserttime1, inserttime2))
        lenx.append(i)
        insert1y.append(inserttime1)
        insert2y.append(inserttime2)
        ax = plt.gca()
        # 去掉边框
        ax.spines['top'].set_color('none')
        ax.spines['right'].set_color('none')
        # 移位置 设为原点相交
        ax.xaxis.set_ticks_position('bottom')
        ax.spines['bottom'].set_position(('data', 0))
        ax.yaxis.set_ticks_position('left')
        ax.spines['left'].set_position(('data', 0))
        plt.ylim(0, 0.0002)
        plt.scatter(lenx, insert1y, c=color[3], edgecolors='r', label='List')
        plt.scatter(lenx, insert2y, c=color[1], edgecolors='b', marker='^', label='Node')
        plt.xlabel('lenth(list)')
        plt.ylabel('time(/s)')
        plt.title('List&Node_insert_analysis')
        plt.legend()
        plt.show()

结果如图:
在这里插入图片描述
python列表的插入操作是线性阶,链表实现列表的插入操作是常数阶。

26. 设计和实现一个实验,比较基于python列表的栈和队列与相应链表实现的性能。

以队列的入队操作为例:

from chapter3.queue import Queue as Q1
from chapter3_answer.t23 import Queue as Q2
import timeit
import random
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

lenx = []
enqueue1y = []
enqueue2y = []
color = ['c', 'b', 'g', 'r', 'm', 'y', 'k', 'w']

if __name__ == '__main__':
    q1 = Q1()
    q2 = Q2()

    for i in range(100, 200000, 5000):
        t1 = timeit.Timer("q1.enqueue(%d)" % i, "from __main__ import random, x,q1")
        t2 = timeit.Timer("q2.enqueue(%d)" % i, "from __main__ import random, q2")
        x = list(range(i))
        for j in x:
            q1.enqueue(j)
        enqueuetime1 = t1.timeit(number=1)
        for m in range(i):
            q2.enqueue(m)
        enqueuetime2 = t2.timeit(number=1)
        print("%d, %15.6f,%15.6f" % (i, enqueuetime1, enqueuetime2))
        lenx.append(i)
        enqueue1y.append(enqueuetime1)
        enqueue2y.append(enqueuetime2)
        ax = plt.gca()
        # 去掉边框
        ax.spines['top'].set_color('none')
        ax.spines['right'].set_color('none')
        # 移位置 设为原点相交
        ax.xaxis.set_ticks_position('bottom')
        ax.spines['bottom'].set_position(('data', 0))
        ax.yaxis.set_ticks_position('left')
        ax.spines['left'].set_position(('data', 0))
        plt.ylim(0, 0.001)
        plt.scatter(lenx, enqueue1y, c=color[3], edgecolors='r', label='List')
        plt.scatter(lenx, enqueue2y, c=color[1], edgecolors='b', marker='^', label='Node')
        plt.xlabel('lenth(list)')
        plt.ylabel('time(/s)')
        plt.title('List&Node_Queue.enqueue()_analysis')
        plt.legend()
        plt.show()

结果如图:
在这里插入图片描述
python列表实现队列的入队操作是线性阶,链表实现队列的入队操作是常数阶。

27. 由于每个节点都只有一个引用指向其后的节点,因此本章给出的链表实现成为单向链表。另一种实现成为双向链表。在这种实现中,每一个节点都有指向后一个节点的引用(通常称为next)和指向前一个节点的引用(通常称为back)。头引用同样也有两个引用,一个指向链表中的第一个节点,另一个指向最后一个节点。请用Python实现双向链表。

from chapter3.node import Node
from chapter3_answer.t15_19 import unorderList

class DNode(Node):
    def __init__(self, initdata):
        super(DNode, self).__init__(initdata)
        self.back = None

    def getBack(self):
        return self.back

    def setBack(self, newback):
        self.back = newback

class DList(unorderList):
    def __init__(self):
        super(DList, self).__init__()

    def add(self, item):

        temp = DNode(item)
        temp.setNext(self.head)
        p = self.head
        if p == None:
            self.head = temp
            print(self.head.getData())
            self.head.setBack(temp)
            self.head.setNext(None)
            self.lenth += 1
        else:
            while p.getNext() != None:
                p = p.getNext()
            temp.setBack(p)
            temp.setNext(self.head)
            self.head.setBack(temp)
            self.head = temp
            self.lenth += 1

if __name__ == '__main__':
    list = DList()
    list.add(1)
    list.add(2)
    list.add(3)
    print(list)
    print(list.head.getBack().getData())
    print(list.head.getNext().getData())

28. 为队列创建一个实现,使得添加操作和移除操作的平均时间复杂度是 O ( 1 ) O(1) O(1)

考虑循环队列:

class CircularQueue:
    def __init__(self, maxsize):
        self.items = [None]*maxsize
        self.maxsize = maxsize
        self.front = 0
        self.rear = 0
        self.length = 0

    def isEmpty(self):
        return self.front == self.rear

    def enqueue(self, item):
        if (self.rear+1) % self.maxsize == self.front:
            return "Error: the queue is full and maxsize = %d"%self.maxsize
        self.rear = (self.rear+1) % self.maxsize
        self.items[self.rear] = item
        self.length += 1
        return self

    def dequeue(self):
        if self.isEmpty():
            return "Error: the queue is none"
        self.front = (self.front + 1) % self.maxsize
        x = self.items[self.front]
        self.items[self.front] = None
        self.length -= 1
        return x

    def size(self):
        return self.length


if __name__ == '__main__':
    deq = CircularQueue(100)
    deq.enqueue(1)
    deq.enqueue(2)
    deq.enqueue(3)
    deq.enqueue(4)
    deq.enqueue(5)
    deq.enqueue(6)

    print(deq.items)
    print(deq.dequeue())
    print(deq.items)
    print(deq.rear)
    print(deq.front)
    for i in range(deq.front+1, deq.rear+1):
        print(deq.items[i])

三、总结

主要学习了栈、队列、链表的构建和应用,以及用随机数模拟概率等。
如:

  1. 用栈求解后序表达式
  2. 队列模拟打印任务,基数排序法
  3. 双端队列检测回文
  • 10
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值