数据结构与算法分析课下实验练习,现记录一下解答过程,欢迎大家批评指正。
声明:本题目来源于西安交通大学电信学院原盛老师,任何单位或个人在使用、转载或引用本题目时,请务必标明出处为“西安交通大学电信学院原盛老师”。
练习三:关于栈
众所周知,栈虽然是一个操作受限的线性表,但是其用途很广泛,栈的数据结构实现非常简单,因此我们只从应用层面熟悉栈。请完成下面二个子任务。
(1) 算数混合表达式计算 表达式不仅能处理整数,还需要处理小数。表达式中涉及的运算符包括+; -; ∗; ÷和 ^(指数)。表达式可以包含圆括号,且允许圆括号的嵌套,因此要处理括号匹配失败的情形。
(2) 寻找连续的股票最大走势区间 在股票市场中,需要识别股价走势中的连续时间段,这些时间段内股价表现出特定的行为模式,如连续上涨、连续下跌或是横盘整理等。这种分析对于技术分析尤为重要,它帮助交易者和投资者理解市场的动向,判断趋势的持续性或反转的可能性。给定一个记录股票价格的数组 prices,需要生成对应的 s 数组,s[i] 中记录的值为 i - j + 1,其中 i 和 j 必须要满足 prices[j::i - 1] 中的每一个值都符合 prices[j] ≤ prices[i]。s 数组中的最大值即为连续上涨的最大区间。如图 1 所示。
设计并实现一个算法完成对给定的 prices 数组上求最大连续上涨时间区间值。如果仅使用最朴实的设计思想,该算法的时间复杂和空间复杂度是多少?如果使用栈设计的算法,其时间复杂度和空间复杂度是多少?
随机生成 10 组数据完成测试。
第一问
第一小问可以这样实现:我们输入一个混合表达式(中缀),然后将其转化成后缀表达式,然后根据后缀表达式计算结果。这里要注意:避免触发计算机自带的计算机制,即我们现在假设计算机只会进行加减乘除和乘方的其中一种计算,并不会进行混合计算。 为了实现这个,我们可以以字符串的形式进行。字符串不会自己进行计算。除此之外,还有一个问题就在与小数和百位数的输入问题,如果是小数的输入那怎么才能让小数成为一个整体呢?举例而言,1.1+3*2.3 这个表达式的输入,因为我们是以字符串的形式输入的,那么如果是整数的形式输入一个索引所对应的就是一个数字。 而现在我们是小数输入,一个索引并不能表示一个小数。或者一个索引并不能表示一个两位数或更多。这里我觉得并不是此问题的关键,所以在输入时,我要求要以空格将数字和字符隔开,使用 split 方法即可以断开。这样就方便了我们的操作,让精力集中在表达式的转换和计算上。
注:输入代数式时要注意英文符号,其次每个数字和字符之间要用空格隔开
#这里先定义算术符的优先性大小,方便后续比较
f={
'+':1,
'-':1,
'*':2,
'/':2,
'^':3,
'(':4
}
x=input('请输入表达式(请使用英文字符,且数字和字符之间用空格隔开,只允许输入小括号):')
x=x.split()
#先检测输入的字符是否合法
kk=[]
for i in range(len(x)):
if x[i]=='(':
kk.append(x[i])
if x[i]==')':
if kk[len(kk)-1]!='(' or len(kk)==0:
print('输入括号不匹配!!')
else: kk.pop()
if len(kk)!=0:
print('输入括号不匹配!!')
else:
a=[]#用于存放后缀表达式
b=[]#用于存放字符
for i in range(len(x)):
if (x[i].isdigit())or ('.' in x[i]):
a.append(x[i])
elif x[i]!=')':
if x[i]=='(':
b.append(x[i])
f[x[i]]=0
continue
if len(b)==0 or f[x[i]]>f[b[len(b)-1]] or x[i]=='^':
b.append(x[i])
continue
while f[x[i]]<=f[b[len(b)-1]]:
a.append(b.pop())
if len(b)==0: break
b.append(x[i])
else:
while b[len(b)-1]!='(':
a.append(b.pop())
f[b[len(b)-1]]=4
b.pop()
if len(b)!=0:
for i in range(len(b)):
a.append(b.pop())
print(a)
#对a进行操作,计算后缀表达式
c=[]
for i in range(len(a)):
if a[i]>='0' and a[i]<='9':
c.append(a[i])
else:
m2=float(c.pop())
m1=float(c.pop())
if a[i]=='+':
c.append(m1+m2)
elif a[i]=='-':
c.append(m1-m2)
elif a[i]=='*':
c.append(m1*m2)
elif a[i]=='/':
c.append(m1/m2)
else: c.append(m1**m2)
print(c[0])
结果输出:
正常情况下输出:
检验括号匹配情况:
第二问
首先明白 s[i]表示的含义: s[i]表示 prices 列表中第 i 个元素结尾且在它之前有多少个连续的元素比它小。
普通算法思想:从 prices[i]开始向前寻找,直到不满足条件结束,记录这个区间的长度。最后返回 s 列表以及列表中的最大值。
如果使用栈的思想:利用栈的话可以直接求得 s 数组的最大值。 其中最关键的一点在与如果从 prices[j]到 prices[i]的区间满足条件,那么不需要去查询这个区间中的任何一个元素为结尾有多大的区间长度满足条件,因为后者的区间长度必然不能大于前者的区间长度(我们要求的是最大长度)这正是优化的地方所在。(但感觉这个栈没有多大关系,不用栈也能写。)
import random
#普通
s=[]
x=[]
for i in range(10):
x.append(random.randint(1,100))
print(x)
for i in range(len(x)):
num=0
k=i
while x[i]>=x[k] and k>=0:
num+=1
k=k-1
s.append(num)
print(max(s),sep='\n')
#栈的思想
stack=[]
maximum=0
i=len(x)-1
while i>=0:
if len(stack)==0 or x[i]<=stack[0]:
stack.append(x[i])
else:
if len(stack)>maximum:
maximum=len(stack)
stack.clear()
stack.append(x[i])
i-=1
if len(stack)>maximum:
maximum=len(stack)
print(maximum)
结果展示:第一行是随机生成的 prices 列表,第二行和第三行输出的是两种算法得出最大区间。
时间复杂度分析: 普通思想情况下,则其时间复杂度为: O(n^2),空间复杂度为 O(1)而对于利用栈来说:它只需要扫描一遍即可得到最大值,所以它的时间复杂度为 O(n),空间复杂度为 O(n)
写作时间匆忙,如有错误请不吝赐教。