声明:本文为CSDN博主「纳梨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
本人只是在学习时加了注释,方便初学者理解代码
原文链接:https: //blog.csdn.net/conan04260426/article/details/127115285
"""1 修改从中序到后序的转换算法,使其能处理异常情况。"""
import string
class Stack: # 一个类就是一个栈
def __init__(self): # 设置一个空栈
self.items = [] # 需要items参数才能添加
def isEmpty(self): # 定义检查栈的方法(它只返回布尔值)
return self.items == []
def push(self, item): # 定义给栈添加元素的方法
self.items.append(item) # 需要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)
def infixToPostfix(infixexpr):
prec = {'*': 3, '/': 3, '+': 2, '-': 2, '(': 1}
opstack = Stack() # 创建对象
postfixList = [] # 用于判断表达式的临时列表(最后要转为字符串返回出来)
count = 0 # 计算器
tokenList = infixexpr.split() # 分割字符串放进列表
lenth = len(tokenList) # 表达式元素的个数
try: # 如果没错
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 # 计算器+1
opstack.push(token) # 入栈
elif token == ')': # 如果是右括号计算器-1(判断括号是否对称)
count -= 1 # 计算器-1
topToken = opstack.pop() # 出栈把值赋值给变量
while topToken != '(': # 不是左括号就循环
postfixList.append(topToken) # 添加到列表
topToken = opstack.pop() # 出栈把值赋值给变量
else:
# 栈不空and栈顶元素的值大于等于当前字典对应的值
while (not opstack.isEmpty()) and (prec[opstack.peek()] >= prec[token]):
postfixList.append(opstack.pop()) # 出栈把值添加的列表
opstack.push(token) # 入栈栈不空
if count != 0: # 计算器不等于0(括号不匹配)
return "Input Error"
while not opstack.isEmpty(): # 栈不空
postfixList.append(opstack.pop()) # 出栈把值添加的列表
return " ".join(postfixList) # 把列表转为字符串返回出来
except: # 反之错了
return "Input Error"
if __name__ == '__main__':
print(infixToPostfix("( A + - V )")) # 只能传全括号表达式
print(infixToPostfix("( A + V )"))
print(infixToPostfix("( ( A + B ) * ( C + D ) )"))
# 2.修改计算后序表达式的算法,使其能处理异常情况
from 栈 import Stack # 导入模块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 5 6 * +"))
"""3.结合从中序到后序的转换算法以及计算后序表达式的算法,
实现直接的中序计算。
在计算时,应该使用两个栈从左往右处理中序表达式标记。
一个栈用于保存运算符,另一个用于保存操作数。"""
from 栈 import Stack # 导入模块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 + 131 )"))
"""3.结合从中序到后序的转换算法以及计算后序表达式的算法,
实现直接的中序计算。
在计算时,应该使用两个栈从左往右处理中序表达式标记。
一个栈用于保存运算符,另一个用于保存操作数。"""
from 栈 import Stack # 导入模块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 + 131 )"))
"""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)
if __name__ == '__main__':
s = Queue()
print(s.isEmpty()) # 检查队列
s.enqueue(5) # 入队
s.enqueue('dog') # 入队
print(s.size()) # 返回队列长度
print(s.dequeue()) # 出队
print(s.size()) # 队列长度
"""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()
# 由实验知:
# 以列表头部做队头的队列入队操作的时间复杂度为常数阶:O(1 11)
# 以列表尾部做队头的队列入队操作的时间复杂度为线性阶:O(n nn)
"""7.实现一个队列,使其添加操作和移除操作的平均时间复杂度为O(1 11)。
这意味着在大多数情况下,两个操作的时间复杂度都是O(1 11),仅在一种特殊情况下,移除操作为O(n nn)。"""
# 【存疑】考虑输入受限的双端队列,即允许在一端进行添加和删除,另一端只允许删除。
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(1)
deq.addRear(2)
deq.addRear(3)
deq.addRear(4)
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
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)
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 # 洗车时间倒计时减去1秒
if self.timeRemaining <= 0: # 洗车时间倒计时为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 # 车型*60*
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("平均等待时间 %6.2f 还有 %3d 没洗." %
(averageWait, carsQueue.size()))
def newwashingTask(): # 生成洗车客人
num = random.randrange(1, 361) # 360/1的机遇来一个
if num == 360: # 如果等于360就生成洗车客人
return True
else:
return False
if __name__ == '__main__':
for i in range(10): # 模拟10次
simulation(3600, 10) # 调用主程序(总时间,洗几辆)
"""" 9. 修改传土豆模拟程序,允许随机计数,从而使每一轮的结果都不可预测"""
import random
class Queue: # 一个类就是一个队列
def __init__(self): # 设置一个队列
self.items = [] # 需要items参数才能添加
def isEmpty(self): # 定义检查队列的方法(它只返回布尔值)
return self.items == []
def enqueue(self, item): # 定义给队列添加元素的方法
self.items.insert(0, item) # 需要item参数才能添加
def dequeue(self): # 定义给队列删除元素的方法
return self.items.pop()
def size(self): # 返回队列元素个数的方法
return len(self.items)
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号数位桶中将值放回主桶
# 。重复整个过程到数字的十位、百位等。在最后一个数位被处理完之后,主桶里面就是排好序的值
class Queue: # 一个类就是一个队列
def __init__(self): # 设置一个队列
self.items = [] # 需要items参数才能添加
def isEmpty(self): # 定义检查队列的方法(它只返回布尔值)
return self.items == []
def enqueue(self, item): # 定义给队列添加元素的方法
self.items.insert(0, item) # 需要item参数才能添加
def dequeue(self): # 定义给队列删除元素的方法
return self.items.pop()
def size(self): # 返回队列元素个数的方法
return len(self.items)
def cardinalitysorted(alist):
result = [] # 最后结果
masterq = Queue() # 创建对象
numslist = [] # 装队列类的空列表
maxnumlen = 0 # 用于计算数字个位,十位,百位等
for i in range(10):
numslist.append(Queue()) # 建10个队列类
for i in range(len(alist)): # 在列表长度里面循环
maxnumlen = max(maxnumlen, len(str(alist[i]))) # 几位数 = (0 < 单个元素长度)
#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): # 循环10次
while not numslist[j].isEmpty(): # 检测10个队列是不是空
masterq.enqueue(numslist[j].dequeue()) # 添加删除队列头部的元素
for i in range(len(alist)): # 在列表长度里循环
result.append(masterq.dequeue()) # 删除队列头部添加到列表
return result
if __name__ == '__main__':
ml = [534, 667, 3215, 57, 4123, 3, 3535, 90]
print(cardinalitysorted(ml))
"""11.HTML 中也存在括号匹配问题。标签有开始和结束两种形式,
并且需要互相匹配才能正确描述网页内容。
写一个程序来检查HTML文档中的标签是否正确匹配。"""
from 栈 import Stack # 导入模块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 就是回文。"""
class Dequeue:
def __init__(self):
self.items = []
# 判空
def isEmpty(self):
return self.items == []
# 从队头添加
def addFront(self, item):
self.items.append(item)
# 从队尾添加
def addRear(self, item):
self.items.insert(0, item)
# 从队头出队
def removeFront(self):
return self.items.pop()
# 从队尾出队
def removeRear(self):
return self.items.pop(0)
# 队大小
def size(self):
return len(self.items)
def palchecker(aString): # 定义函数
chardeque = Dequeue() # 创建对象
for ch in aString: # 遍历字符串
if ch == ' ': # 如果遇到空字符
continue # 绕过去继续执行下面代码
chardeque.addRear(ch) # 入队
matched = True # 结果默认为真
while matched and chardeque.size() > 1: # 结果为真和队列长度大于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))
"""14 实现remove 方法,使其能正确处理待移除元素不在列表中的情况
17 实现__str__方法,使列表按照Python 的方式来显示(使用方括号)
18 实现无序列表抽象数据类型剩余的方法:append、index、pop 和insert。
19 实现UnorderedList 类的slice 方法"""
class Node: # 节点类
def __init__(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 unorderList: # 链表类
def __init__(self):
self.head = None # 表头
self.lenth = 0 # 长度
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 # 长度-1
except:
print("待移除的元素不在列表中")
def __str__(self): # 使列表按python来显示
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 + ']' # 返回字符串
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 # 计数器+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 # 长度-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: # 如果你传入的下标等于0
temp.setNext(self.head) #
self.head = temp # 你传入的就成了表头
self.lenth += 1 # 长度+1
return self # 返回对象
elif idx < 0: # 下标小于0就报错
return "Input Error"
else: # 反之 向前蠕动到指定下标处
for i in range(idx):
pre = p
p = p.getNext()
pre.setNext(temp) # 更改第二个表头下一个引用为新节点
temp.setNext(p) # 更改新节点下一个引用为表头
self.lenth += 1 # 长度+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 # 新链表长度+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
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)
print(mylist)
print(mylist.index('23')) # 返回元素下标
# p = mylist.head
print(mylist.pop()) # 尾部删除
print(mylist)
mylist1 = mylist.insert(2, 66) # 指定下标添加
print(mylist1)
mylist2 = mylist.slice(3, 5) # 获取链部某一段数据
print(mylist2)
list2 = unorderList() # 实现尾部添加
list2.add(1)
list2.add(2)
mylist.append(list2)
print(mylist)
"""20. 实现有序列表抽象数据类型剩余的方法。"""
class Node:
def __init__(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 orderList: # 链表类
def __init__(self):
self.head = None # 表头
self.lenth = 0 # 长度
def __str__(self): # 使列表按python来显示
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 + ']' # 返回字符串
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 append(self, alist): # 定义添加方法
newlist = self # 把类赋值给临时类
q = alist.head # 把表头赋值给临时表头
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 # 计数器+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 # 长度-1
return p.getData()
else:
self.head = None # 表头等于空
self.lenth = 0 # 就是个空链表
return p.getData() # 返回表头数据
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 # 新链表长度+1
while j <= stop and p: # 从起点到结束点循环
pre = p # 向前蠕动
p = p.getNext()
j += 1
pre.setNext(None) # 更改第二个表头下一个引用为空
return templist # 返回新链表
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(90)
mylist.add(80)
mylist.add(70)
mylist.add(60)
mylist.add(50)
mylist.add(20)
print(mylist)
list2 = orderList() # 尾部添加
list2.add(4)
list2.add(35)
list2.add(11)
print(list2)
mylist.append(list2)
print(mylist)
print(mylist.index('35')) # 返回元素下标
mylist.pop() # 尾部删除
print(mylist)
mylist.remove(20) # 指定删除
print(mylist)
print(mylist.search(80)) # 查找元素在不在
print(mylist.length()) # 判断个数
"""21 思考有序列表和无序列表的关系。
能否利用继承关系来构建更高效的实现?试着实现这个继承结构"""
# 基本操作只有添加不一样,所以只需重写添加节点方法
from 链表 import * # 导入模块中所有类
class OrderList(UnorderedList):
def __init__(self):
super().__init__()
# 添加节点
def add(self, item): # 添加节点(数据项)
current = self.head # 设置第一个表头为空
previous = None # 设置第二个表头为空(表示还没有)
stop = False # 设置停止为假(不停止)
while current != None and not stop: # 如果第一个表头还有下个引用项而且没停止就循环
if current.getData() > item: # 如果第一个表头的数据项大于了输入的数据项
stop = True # 停止
else: # 反之(向前蠕动)
previous = current # 把第一表头赋值给第二表头
current = current.getNext() # 第一表头的引用项赋值给第一表头
temp = Node(item) # 创建对象
if previous == None: # 如果第二标头为空
temp.setNext(self.head) # 引用项为第一表头的数据项
self.head = temp # 把新表头设置为表头
else:
temp.setNext(current) # 引用项为第一表头的数据项
previous.setNext(temp) # 第二标头的引用项为导入数据的数据项
mylist = OrderList() # 创建对象
mylist.add(67) # 增加
mylist.add(35)
mylist.add(97)
mylist.add(22)
print(mylist.showlist())
print(mylist.remove(35)) # 删除
print(mylist.showlist())
print(mylist.search(35)) # 查找元素在不在
print(mylist.length()) # 返回个数
"""22. 使用链表实现栈"""
from 链表 import * # 导入模块里面全部内容
class Stack(unorderList): # 定义栈(继承链表)
def __init__(self): # 属性
super().__init__() # 继承链表的属性
def push(self, item): # 入栈
return super().add(item)
def pop(self): # 出栈
p = self.head
if p == None:
return "列表为空"
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.size()) # 返回栈长度
print(mylist.pop()) # 出栈
print(mylist.peek()) # 返回栈顶端元素
print(mylist)
"""23.使用链表实现队列。"""
from 链表 import * # 导入模块里面全部内容
class Queue(unorderList): # 定义队列
def __init__(self): # 属性
super().__init__() # 继承链表的属性
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()) # 长度
print(q.isEmpty()) # 判空
"""24. 使用链表实现双端队列。"""
from 链表 import * # 导入模块里面全部内容
class Dequeue(unorderList): # 定义双端队列
def __init__(self):
super().__init__() # 继承链表的属性
def isEmpty(self): # 判空
return super().isEmpty()
def addFront(self, item): # 从队头添加
p = self.head # 把表头赋值给变量
temp = Node(item) # 创建节点
if p == None: # 表头等于空
return super().add(item) # 继承链表的添加方法
else: # 反之
while p.getNext() != None: # 表头的下一个引用不等于空就循环
p = p.getNext() # 向前蠕动
p.setNext(temp) # 更改表头的下一个引用为你传入的值
self.lenth += 1 # 长度+1
def addRear(self, item): # 从队尾添加
return super().add(item) # 继承链表的添加方法
def removeFront(self): # 从队头出队
return super().pop() # 继承链表的尾部删除
def removeRear(self): # 从队尾出队
p = self.head # 把表头赋值给变量(表头)
if p == None: # 表头等于空
return "列表为空"
else: # 反之
pre = p # 表头赋值给第二表头
p = p.getNext() # 把表头下一个引用项赋值给表头
self.head = p # 表头就又成了表头
self.lenth -= 1 # 长度-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.addRear(5)
print(deq)
print(deq.removeFront()) # 从队头出
print(deq.removeRear()) # 从队尾出
print(deq.size()) # 队列长度
print(deq.isEmpty()) # 判空
print(deq)
"""25. 设计和实现一个实验,比较用链表实现的列表与Python列表的性能。
以列表的插入insert为例:"""
from 链表 import * # 导入模块里面全部内容
import random # 导入随机模块
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): # 100到200000之间步长为500循环
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队列与相应链表实现的队列性能对比。
以队列的入队操作为例:"""
import pandas as pd # 导入数据处理库
import numpy as np # 导入科学计算处理库
from 队列 import Queue as Q1 # 导入队列模块里面Queue类,起个别名
from 链表实现队列 import Queue as Q2 # 导入链表实现队列模块里面Queue类,起个别名
import random # 导入随机模块
import timeit # 导入时间库(段代码的运行时间)
import matplotlib.pyplot as plt # 导入图表库(生成图表)
"""生成图表用的(不会,不解释)"""
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): # 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. 请用Python实现双向链表。"""
from 链表 import * # 导入链表模块
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 # 长度+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 # 长度+1
if __name__ == '__main__':
list = DList() # 创建对象
list.add(1) # 添加
list.add(2)
list.add(3)
list.add(4)
list.add(5)
list.add(6)
print(list)
print(list.head.getBack().getData()) # 打印 表头的上一个节点引用项
print(list.head.getNext().getData()) # 打印 表头的下一个节点引用项
"""28. 为队列创建一个实现,使得添加操作和移除操作的平均时间复杂度是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): # 判空
if self.front == self.rear: #(前后指针指向同一个卡槽为true)
return True # 无值
else:
return False # 有值
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 # 元素长度+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 # 元素长度-1
return x # 返回相应卡槽号的值
def size(self): # 返回长度
return self.length
if __name__ == '__main__':
deq = CircularQueue(30) # 创建对象(长度)
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) # 打印前指针
print(deq.isEmpty()) # 判空
for i in range(deq.front+1, deq.rear+1): # 在前后指针间循环
print(deq.items[i]) # 迭代出列表相应下标的值