算法6:设计中常用的武器-栈

算法就是设计,而设计无处不在,故算法无处不在,但这是废话,关键还是,要把握设计的套路,如果能发明套路就更不得了。设计套路中,有一个套路,是定制一个数据结构,就相当于定制出一个专用的厉害武器,然后用于解决特定的问题。

为了解决不同的问题,你可以定制出不同的数据结构。什么是数据结构?就是数据的组织结构,有特点的结构。在诸多数据结构中,有一些是通用的,也就是可以用于很多问题场景,因此它也是常用的。

常用的数据结构中,有一个结构,叫作“栈”。栈,能独立作为一个数据结构,在于它有自己的特点--由此可见,有特点才能自立门派。

栈的特点,是操作都在同一个地方进行,这个地方叫栈顶。入栈、出栈,都在栈顶进行,最先被处理的是最后进栈的元素,“来得早不如来得巧”,这可不是排队。

注意,数据结构的栈,跟c语言内存管理中的“栈”不是一个概念。

栈的封装实现,哪一门语言可以做到。

为了简化语言的细节与难度,这里选择python,只因为它的易用性。而简化语言的难度,是为了把精力放在算法或数据结构的设计上,而不是纠结于“内存怎么释放”、“怎么自动检测类型”之类的节外生枝的问题上,专注很重要!

(一)栈的实现

python实现栈,很简单,用list(列表)即可。

入栈:s.append('hello stack')
出栈:s.pop()
栈是否为空:not s
偷看一下栈顶:s[-1]
栈的长度:len(s)

比如:

s=[]
s.append(8)
len(s)      #1
s.pop()     #返回8
not s       #True,为空
s.append('hello')
s.append(False)
s.append(8.9)
len(s)      #3
s[-1]       #8.9
len(s)      #3
s.pop()     #8.9
len(s)      #2
not s       #False

pop或append后,栈顶的位置都在变化。

(二)栈的应用

任何一个数据结构,都是因为有应用的场景才存在,也就是时势造英雄。但基于这个数据结构,是可以创造出新的算法的,英雄也可造时势。

栈也不例外。

下面举例说说它的应用场景。

(1)判断左右符号是否配对

左符号:([{,右符号:)]},配对的情况如:‘([]){()}‘,不配对的情况如:‘[{]}]‘。

用栈来理解就是:

遍历所有字符。
遇左符号则入栈;遇右符号则出栈(如果为空则直接返回False),出栈返回的字符如果与右符号不配对则返回False,如果配对则继续下一个字符。
所有字符遍历完后,栈非空则返回False,否则返回True。
def sybol_match(str):
    L=['(','{','['];
    R=[')','}',']'];
    s=[]
    for c in str:
        if c in L:
            s.append(c)
        else:
            if not s:
                return False
            a=s.pop()
            lp = L.index(a)
            rp = R.index(c)
            if lp!=rp:
                return False
    return not s

(2)计算后缀表达式

计算一个表达式时,表达式可以以中缀或后缀的方式录入,而后缀表达式由于不使用括号而简化处理,所以是一个普遍的选择。

补充一下知识点,中缀表达式是我们常用的表达方式,也就是把符号放在数字中间,比如3+4,而前缀或后缀是计算机喜欢的表达方式,因为它更易于解析。前缀就是把符号放在数字前面,比如+ 3 4,而后缀就是符号在数字后面,比如3 4 +。

再比如:

中缀:12*(2/2)  后缀:12 2 2 / *
中缀:10-(2*3) 后缀:10 2 3 * -
中缀:(3-2)*(9/3)+5     后缀:3 2 - 9 3 / * 5 + 

用栈来理解就是:

遍历所有分割项(以空格切分)。
遇到数字则入栈;遇到操作符出栈两次(这里简化为都是二元操作,第一次出栈的为参数2,第二次为参数1),并进行运算,再把结果入栈。
遍历完所有分割项后,返回栈中内容(只有一个值)。
operators = {
        '+' : lambda p1, p2: p1+p2,
        '-' : lambda p1, p2: p1-p2,
        '*' : lambda p1, p2: p1*p2,
        '/' : lambda p1, p2: p1/p2,
        }
def calc_postfix(str):
    expr = str.split()
    s = []
    for e in expr:
        if e.isdigit():
            s.append(int(e))
        else:
            f = operators[e]
            p2 = s.pop()
            p1 = s.pop()
            s.append(f(p1, p2))

    return s.pop()

(3)背包问题

有若干个物品,每一个物品都有重量。背包有最大容量限制,求刚好装满背包最大容量的所有解。

比如:

物品名称    重量
物品0     1kg
物品1     8kg
物品2     4kg
物品3     3kg
物品4     5kg
物品5     2kg

背包最大可以装10kg,那可能的解是:[0,2,3,5]、[1,5]等。

用栈来理解就是:

尽情地装(按物品顺序,只要能装得下就装),如果剩余容量刚好为0或者之后的各个物品都装不下了,则出栈,即拿掉最后的一个物品k,再继续从k+1个物品开始装。
栈为空而且填装的物品的索引已经超出范围,则结束循环。
由于,总会一直出栈到一个物品都没有,再从下一个物品开始填装,所以一定会出现栈为空且没有物品可装的情况。
def knapsack(w, ws):
    """
    w --背包容量
    ws --物品重量列表 [1, 3, ..]
    """
    ret = []
    s = []
    i = 0
    cnt = len(ws)
    rest = w
    while s or i < cnt:  # 栈为空或者还有得装
        while i < cnt and rest > 0:  # 还有得装且还有容量
            if rest >= ws[i]:  # 装得下就装
                s.append(i)
                rest -= ws[i]
            i += 1   # 不管当前的是否装得下,都要尝试下一个
        if rest == 0:
            ret.append(s[:])  # one solution
        i = s.pop()
        rest += ws[i]
        i += 1
    return ret

if __name__ == '__main__':
    # print(sybol_match('[{()}]{}[()]()'))
    # print(sybol_match('[({}])'))
    # print(calc_postfix('12 2 2 / *'))
    # print(calc_postfix('3 2 - 9 3 / * 5 +'))
    ret = knapsack(10, [1, 8, 4, 3, 5, 2])
    print(ret)

(三)总结

工具的价值在于恰当的使用。栈,一个简单的工具,可用于某类问题的解决。

但是,这里的重点不是怎么设计栈这个数据结构,而是,你要有一个意识,就是对于特定的问题,有可能要设计一个专用的数据结构并使用它,当然,通用的数据结构也是一个办法。



原文地址:https://www.cnblogs.com/freeself/p/10837673.html

时间: 2024-10-16 04:05:11

算法6:设计中常用的武器-栈的相关文章

网页设计中常用的Web安全字体

但多数情况下,考虑各个因素的影响我们还是在尽量充分利用这些默认调用的字体实现CSS的编写,这里整理了19个Web安全字体,让你无需任何顾虑的情况下畅快使用. 1,  Arial 微软公司的网页核心字体之一,最常用的sans-serif字体,当字号很小时不容易阅读.但是,大写的“I”和小写的“l”是无法区别的,你可以考虑用Tahoma字体来替代.(苹果系统没有这种字体,但有一种对应于Arial的字体叫Helvetica,它是MAC机上与Arial 字体最相似的WEB字体,是别一种非衬线字体.它是一

网页设计中常用的19个Web安全字体

在Web编码中,CSS默认应用的Web字体是有限的,虽然在新版本的CSS3,我们可以通过新增的@font-face属性来引入特殊的浏览器加载字体.但多数情况下,考虑各个因素的影响我们还是在尽量充分利用这些默认调用的字体实现CSS的编写,这里整理了19个Web安全字体,让你无需任何顾虑的情况下畅快使用. 1,  Arial 微软公司的网页核心字体之一,最常用的sans serif字体,当字号很小时不容易阅读.但是,大写的“I”和小写的“l”是无法区别的,你可以考虑用Tahoma字体来替代.(苹果系

网站设计中常用的一些jq效果

只做会做网站设计不会前端是不行的,现在很多网站设计师都会精通前端CSS+jquery,但是今天要说的是是我个人在一家厦门网站设计公司中经验笔记,都是很实用的,希望能帮助网站设计者们,现在越来越多的网站运用上了Jquery技术,特别是在国外网站上Jquery运用的已经很成熟了,不紧提升了网站的精美度与用户之间的互动效果,把Jquery运用到网站的局部效果上,还能大大的提升网站页面上的体验效果.目前我们公司给大多客户网站上都有体现这个效果,下面我就为大家分享下提升网站体验效果的5个Jquery效果,

网页设计中常用的CSS命名规则整理

头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 或 wrap 左右中:left right center 登录条:loginbar 标志:logo 广告:banner 页面主体:main 热点:hot 新闻:news 下载:download 子导航:subnav 菜单:menu 子菜单:submenu 搜索:search 友情链接:friendlink 页脚:foote

[实用向] 算法笔试题中常用的一些函数

1.pow 幂运算(math.h) pow(2,n);//2^n 2.sqrt  开方运算 (math.h) sqrt(n) //开方 x*x = n,返回x https://support.office.com/zh-cn/article/SQRT-%E5%87%BD%E6%95%B0-654975c2-05c4-4831-9a24-2c65e4040fdf -----------------------------随时更新-------------------------------- 原文

ACM中常用算法----字符串

ACM中常用算法--字符串 ACM中常用的字符串算法不多,主要有以下几种: Hash 字典树 KMP AC自动机 manacher 后缀数组 EX_KMP SAM(后缀自动机) 回文串自动机 下面来分别介绍一下: 0. Hash 字符串的hash是最简单也最常用的算法,通过某种hash函数将不同的字符串分别对应到不同的数字.进而配合其他数据结构或STL可以做到判重,统计,查询等操作. #### 字符串的hash函数: 一个很简单的hash函数代码如下: ull xp[maxn],hash[max

pageadmin CMS网站建设教程:网页设计的常用参数

由于网络速度问题,我们需要考虑图片大小对传输速度的影响,如果图片太大就会影响浏览速度,访问者很快就会对这个网站失去了兴趣,只有充分了解图片质量与下载速度的关系,并了解不同的文件格式,才能更有效的表达内容.如何控制图片质量而不影响网页加载速度,我们今天陈述一点网页设计中常用到的参数:1.分辨率理解图像分辨率可以直接控制文件大小和下载速度,进而影响访问者的人数,创建WEB 图片的小.快.好.显示器的分辨率起绝对性作用,大多数显示器使用的是1024*768的分辨率,因为要通过显示器显示页面,所以用高分

[转]数据库设计中的常用技巧

本文介绍了数据库设计中的14个技巧,这是许多人在大量的数据库分析与设计实践中,逐步总结出来的-- 下述十四个技巧,是许多人在大量的数据库分析与设计实践中,逐步总结出来的.对于这些经验的运用,读者不能生帮硬套,死记硬背,而要消化理解,实事求是,灵活掌握.并逐步做到:在应用中发展,在发展中应用. 1. 原始单据与实体之间的关系 可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体.在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个

推荐系统中常用算法 以及优点缺点对比

推荐系统中常用算法 以及优点缺点对比 在 推荐系统简介中,我们给出了推荐系统的一般框架.很明显,推荐方法是整个推荐系统中最核心.最关键的部分,很大程度上决定了推荐系统性能的优劣.目前,主要的推荐方法包括:基于内容推荐.协同过滤推荐.基于关联规则推荐.基于效用推荐.基于知识推荐和组合推荐. 一.基于内容推荐 基于内容的推荐(Content-based Recommendation)是信息过滤技术的延续与发展,它是建立在项目的内容信息上作出推荐的,而不需要依据用户对项目的评价意见,更多地需要用机 器