《problem-solving-with-algorithms-and-data-structure-using-python》的中文版翻译

读书笔记
一、关于栈:栈操作

  • Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
  • push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
  • pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
  • peek() 从栈返回顶部项,但不会删除它。不需要参数。 不修改栈。
  • isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
  • size() 返回栈中的 item 数量。不需要参数,并返回一个整数
image.png

二、Python实现栈
当我们给抽象数据类型一个物理实现时,我们将实现称为数据结构
抽象数据类型:栈
抽象数据类型的选择的实现:创建一个新类
栈操作实现为类的方法
栈的实现 由于栈是一个表, 因此任何实现表的方法都能实现栈

[1]
[1]:https://www.sogou.com/link?url=DOb0bgH2eKih6L6-zjc6o4XQwy2fLmFtVp0RnDKnmVWGBAHeZ71z-AZFJ5UQUXQ3&query=%E6%A0%88%E6%93%8D%E4%BD%9C%E5%AE%9E%E7%8E%B0%E4%B8%BA%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82
ActiveCode 1

class Stack:# 创建一个栈
    def __init__(self):

        self.items = []

    def isEmpty(self):

        return selt.items == []

    def push(self, item):
        self.items.append(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)

python test.py——测试通过
使用栈:
通过实例化 Stack 类执行 Table 1中的操作。
注意,Stack 类的定义是从 pythonds 模块导入的
ActiveCode 2

from pythonds.basic.stack import Stack

s = Stack()

print(s.isEmpty())

s.push(4)

s.push('dog')

print(s.peek())

s.push(True)

print(s.size())

print(s.isEmpty())

s.push(8.4)

print(s.pop())

print(s.pop())

print(s.size())
运行结果:
python test.py
True
dog
3
False
8.4
True
2```

小结:
1.栈实现:创建类
2.栈操作实现:创建类的方法
3.Python的列表作为底层实现
问题:
1.ImportError: No module named 'pythonds'
解决:cmd-输入pip install pythonds安装该模块
小知识:
1958年,JohnMcCarthy设计了Lisp语言。
2.1 栈解决实际问题
 Lisp 使用大量的圆括号是臭名昭著的
如 Lisp 的构造

(defun square(n)
(* n n))

这段代码定义了一个名为 square 的函数,它将返回参数的 n 的平方
ActiveCode 1

from pythonds.basic.stack import Stack

A 如何编写一个算法,能够从左到右读取一串符号,并决定符号是否平衡。

def parChecker(symbolString):

s = Stack()

balanced = True

index = 0

while index < len(symbolString) and balanced:

    symbol = symbolString[index]

    if symbol == "(":
        s.push(symbol)
    else:

        if s.isEmpty():

            balanced = False
        else:

            s.pop()

    index = index + 1

if balanced and s.isEmpty():

    return True
else:

    return False

print(parChecker('((()))'))
print(parChecker('(()'))

结果;
True
False
2.2 符号匹配
在 Python 中,方括号 [ 和 ] 用于列表,花括号 { 和 } 用于字典。括号 ( 和 ) 用于元祖和算术表达式
现在不仅要考虑开始与结束符号是否匹配,还需要保证符号的匹配类型,如()和[]
ActiveCode 1

from pythonds.basic.stack import Stack

def parChecker(symbolString):

s = Stack()

balanced = True

index = 0

while index < len(symbolString) and balanced:

    symbol = symbolString[index]
    # 如果在索引出匹配,则将索引的值——即右括号)赋给变量

    if symbol in "([{":

        s.push(symbol)

    else:

        if s.isEmpty():

            balanced = False

        else:
            top = s.pop()

            if not matches(top, symbol):

                balanced = False
    index = index + 1

if balanced and s.isEmpty():

    return True

else:

    return False

def matches(open, close):

opens = "([{"

closers = ")]}"

return opens.index(open) == closers.index(close)

print(parChecker('{{([][])}()}'))
print(parChecker('[{()]'))

运行结果:
True
False
小结:
1.栈的应用:栈是计算机语言结构处理非常重要的数据结构

2.3 十进制转换成二进制:“除 2”算法,它用栈来跟踪二进制结果的数字
“除 2” 算法假定我们从大于 0 的整数开始。不断迭代的将十进制除以 2,并跟踪余数。第一个除以 2 的余数说明了这个值是偶数还是奇数。偶数有 0 的余数,记为 0。奇数有余数 1,记为 1.我们将得到的二进制构建为数字序列,第一个余数实际上是序列中的最后一个数字。见 Figure 5 , 我们再次看到了反转的属性,表示栈可能是解决这个问题的数据结构。

![image.png](http://upload-images.jianshu.io/upload_images/5172856-a81fea609c2f9656.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
ActiveCode 1

from pythonds.basic.stack import Stack

def divideBy2(decNumber):

remstack = Stack() # 创建一个栈的实例



while decNumber > 0:
    # 内置的模运算符 % 来提取余数

    rem = decNumber % 2
    # 将余数压到栈上

    remstack.push(rem)

    # 商

    decNumber = decNumber // 2
    # 初始二进制字符串为空



binString = ""

如果栈不空

while not remstack.isEmpty():

不明白:二进制字符串= 二进制字符串 + 栈中弹出的字符串???

    binString = binString + str(remstack.pop())

return binString

print(divideBy2(42))

扩展:扩展以执行任何基数的转换
修改 divideBy2 函数,使它不仅能接受十进制参数,还能接受预期转换的基数。‘除 2’ 的概念被简单的替换成更通用的 ‘除基数’

from pythonds.basic.stack import Stack

def baseConverter(decNumber, base):

digits = "0123456789ABCDEF"

remstack = Stack()

while decNumber > 0:

    rem = decNumber % base

    remstack.push(rem)

    decNumber = decNumber // base

newString = ""

while not remstack.isEmpty():

    newString = newString + digits[remstack.pop()]

return newString

print(baseConverter(25, 2))
print(baseConverter(25, 16))

运行结果:
11001
19
小结:
十进制化为二进制:栈实现 “除 2” 算法,栈的反转属性和不断地迭代
三步:创建不断除以2的函数,提取余数,将余数压入栈中,最后构造出一个二进制字符串
2.4 中缀前缀和后缀表达式
一种保证不会对操作顺序产生混淆的表达式的方法是创建一个称为完全括号表达式的表达式。
计算机需要准确知道要执行的操作符和顺序。一种保证不会对操作顺序产生混淆的表达式的方法是创建一个称为完全括号表达式的表达式。这种类型的表达式对每个运算符都使用一对括号。括号没有歧义的指示操作的顺序。也没有必要记住任何优先规则

前缀表达式符号要求所有运算符在它们处理的两个操作数之前
后缀要求其操作符在相应的操作数之后
A+B*C 将在前缀中写为 + A * B C ,乘法运算符紧接在操作数 B 和 C 之前,表示 * 优先于 +,然后加法运算符出现在 A 和乘法的结果之前

在后缀中,表达式将是 A B C * +,再次,操作的顺序被保留,因为 * 紧接在 B 和 C 之后出现,表示 * 具有高优先级,+ 优先级低。

![image.png](http://upload-images.jianshu.io/upload_images/5172856-740452352a661c8a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
中缀表达式 

前缀和后缀中,强制先加法
而
中缀需要括号,在乘法之前强制执行加法
![image.png](http://upload-images.jianshu.io/upload_images/5172856-3b158af1f39091c2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

为什么在前缀和后缀的时候不需要括号了呢?答案是操作符对于他们的操作数不再模糊,只有中缀才需要括号,前缀和后缀表达式的操作顺序完全由操作符的顺序决定。
2.4.1  中缀表达式转换前缀和后缀
使用特定方法在中缀表达式和等效前缀和后缀表达式符号之间进行转换
考虑的第一种技术使用前面讨论的完全括号表达式的概念
(A +(B * C)):将*移动到C后的右括号除,删除与其相匹配的左括号
得到 B C *,我们实际上已经将子表达式转换为后缀符号
加法运算符也被移动到其相应的右括号位置并且匹配的左括号被去除,
则将得到完整的后缀表达式
同样的将*和+移动到左括号的位置,删除与其相对应的右括号,我们得到前缀符号
所以为了转换表达式,无论是对前缀还是后缀符号,先根据操作的顺序把表达式转换成完全括号表达式
然后将包含的运算符移动到左或右括号的位置,具体取决于需要前缀或后缀符号。+
这里面有个更复杂的例子, (A + B) * C - (D - E) * (F + G)
 ,Figure 8 显示了如何转换为后缀和前缀。

![image.png](http://upload-images.jianshu.io/upload_images/5172856-dff8dd2046bd4cac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2.4.3 中缀转后缀通用法

我们需要开发一个算法来将任何中缀表达式转换为后缀表达式
当我们看到左括号时,我们保存它
当右括号出现时,可以从栈中弹出操作符。
当我们从左到右扫描中缀表达式时,我们将使用栈来保留运算符
反转属性:堆栈的顶部将始终是最近保存的运算符
每当我们读取一个新的运算符时,我们
需要考虑:该运算符如何与已经在栈上的运算符(如果有的话)比较优先级
创建一个名为 opstack 的空栈以保存运算符。给输出创建一个空列表。
通过使用字符串方法拆分将输入的中缀字符串转换为标记列表。
从左到右扫描标记列表。
如果标记是操作数,将其附加到输出列表的末尾。
如果标记是左括号,将其压到 opstack 上。
如果标记是右括号,则弹出 opstack,直到删除相应的左括号。将每个运算符附加到输出列表的末尾。
如果标记是运算符,*,/,+或 - ,将其压入 opstack。但是,首先删除已经在 opstack 中具有更高或相等优先级的任何运算符,并将它们加到输出列表中。
当输入表达式被完全处理时,检查 opstack。仍然在栈上的任何运算符都可以删除并加到输出列表的末尾。
展示了对表达式 A * B + C * D 的转换算法。注意,第一个 * 在看到 + 运算符时被删除。另外,当第二个 * 出现时, + 保留在栈中,因为乘法优先级高于加法。在中缀表达式的末尾,栈被弹出两次,删除两个运算符,并将 + 作为后缀表达式中的最后一个运算符。

![image.png](http://upload-images.jianshu.io/upload_images/5172856-742b72b976206c20.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
中缀转后缀通用法
在 Python 中编写算法,我们使用一个名为 prec 的字典来保存操作符的优先级。这个字典将每个运算符映射到一个整数,可以与其他运算符的优先级(我们使用整数3,2和1)进行比较。左括号将赋予最低的值。这样,与其进行比较的任何运算符将具有更高的优先级,将被放置在它的顶部。第15行将操作数定义为任何大写字符或数字
 
ActiveCode 1

from pythonds.basic.stack import Stack

def infixToPostfix(infixexpr):

prec = {}

# 名为 prec 的字典来保存操作符的优先级
prec["*"] = 3

prec["/"] = 3

prec["+"] = 2

prec["-"] = 2

prec["("] = 1

opStack = Stack()

postfixList = []

tokenList = infixexpr.split()



for token in tokenList:

    if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in  "0123456789":

        postfixList.append(token)

    elif token == '(':

        opStack.push(token)

    elif token == ')':

        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)


    while not opStack.isEmpty():

        postfixList.append(opStack.pop())

    return "".join(postfixList)

print(infixToPostfix("A * B + C * D"))
print(infixToPostfix("( A + B ) * C - ( D - E ) * ( F + G )"))

print(infixToPostfix("A * B + C * D"))
print(infixToPostfix("( A + B ) * C - ( D - E ) * ( F + G )"))
print(infixToPostfix("( A + B ) * ( C + D )"))
print(infixToPostfix("( A + B ) * C"))
print(infixToPostfix("A + B * C"))
运行结果

E:\ScienceSoft\Python\project\alien_invasion>python test.py
A
(
A
(
(
(
A
程序有错

from pythonds.basic.stack import Stack

def infixToPostfix(infixexpr):
    prec = {}
    prec["*"] = 3
    prec["/"] = 3
    prec["+"] = 2
    prec["-"] = 2
    prec["("] = 1
    opStack = Stack()
    postfixList = []
    tokenList = infixexpr.split()

    for token in tokenList:
        if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789":
            postfixList.append(token)
        elif token == '(':
            opStack.push(token)
        elif token == ')':
            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)

    while not opStack.isEmpty():
        postfixList.append(opStack.pop())
    return " ".join(postfixList)

print(infixToPostfix("A * B + C * D"))
print(infixToPostfix("( A + B ) * C - ( D - E ) * ( F + G )"))
print(infixToPostfix("( A + B ) * ( C + D )"))
print(infixToPostfix("( A + B ) * C"))
print(infixToPostfix("A + B * C"))
A B * C D * +
A B + C * D E - F G + * -
A B + C D + *
A B + C *
A B C * +

附录:
https://facert.gitbooks.io/python-data-structure-cn

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,387评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,845评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,091评论 0 246
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,308评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,662评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,795评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,008评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,466评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,687评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,181评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,531评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,177评论 3 239
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,126评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,862评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,734评论 2 274

推荐阅读更多精彩内容

  • 栈的规则 先进后出。如:依次入栈顺序为:A,B,C,D;怎出栈顺序为:D,C,B,A . 二叉树和表达式 表达式的...
    zhangivon阅读 752评论 0 0
  • 本章将会介绍 模块和源文件访问级别访问控制语法自定义类型子类常量、变量、属性、下标构造器协议扩展泛型类型别名位运算...
    寒桥阅读 843评论 0 2
  • 136.泛型 泛型代码让你可以写出灵活,可重用的函数和类型,它们可以使用任何类型,受你定义的需求的约束。你可以写出...
    无沣阅读 1,395评论 0 4
  • 高级运算符 文档地址 作为 基本运算符 的补充,Swift 提供了几个高级运算符执行对数传值进行更加复杂的操作。这...
    hrscy阅读 802评论 0 2
  • 成都的深秋 坐在深秋的夜深深的成都 坐在一个小巷里听着树叶一片片敲打土地的声音 听着那些灯红酒绿起起伏伏 听着那些...
    品格飞扬阅读 339评论 0 0