ADT Stack python代码实现
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return self.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)
栈的应用:简单的括号匹配
首先,每个开括号(左括号)要恰好对应一个闭括号(右括号);
其次,每对开闭括号要正确的嵌套
正确的括号:(()()()()),(((()))),(()((())()))
错误的括号:((((((()),())),(()()(()
下面看看如何构造括号匹配识别算法 从左到右扫描括号串。
最新打开的左括号,应该匹配最先遇到的右括号
这样,第一个左括号(最早打开),就应该匹配最后一个右括号(最后遇到)
这种次序反转的识别,正好符合栈的特性!
def par_checker(symbol_string):
s = []
is_legal = True
index = 0
while index < len(symbol_string) and is_legal:
symbol = symbol_string[index]
if symbol == "(":
s.append(symbol)
else:
if not s:
is_legal = False
else:
s.pop()
index += 1
return is_legal and s == []
print(par_checker("()()()((()))")) # True
print(par_checker("((()")) # False
方法二
def par_checker(symbols):
stack = []
is_valid = True
for symbol in symbols:
if symbol == '(':
stack.append(symbol)
else:
if stack:
stack.pop()
else:
is_valid = False
break
return is_valid and stack == []
def match(open, close):
pass
print(par_checker("()()()((()))")) # True
print(par_checker("((()")) # False
在实际的应用里,我们会碰到更多种括号 如python中列表所用的方括号“[]”字典所用的花括号“{}” 元组和表达式所用的圆括号“()”
这些不同的括号有可能混合在一起使用,因此就要注意各自的开闭匹配情况
❖ 下面这些是匹配的
{ { ([][] )}()}
[ [ {{(() )}}]] [ ] [][]( ){}
❖ 下面这些是不匹配的
( [ )] ((()]) )
[ { ()]
def par_checker(symbol_string):
s = []
is_legal = True
index = 0
while index < len(symbol_string) and is_legal:
symbol = symbol_string[index]
if symbol in "([{": # 修改处1
s.append(symbol)
else:
if not s:
is_legal = False
else:
top = s.pop() # 修改处2
if not match(top, symbol):
is_legal = False
index += 1
return is_legal and s == []
def match(open, close):
opens = "([{"
closes = ")]}"
return opens.index(open) == closes.index(close)
print(par_checker("{{([][])}()}")) # True
print(par_checker("[{()]")) # False
方法二
def par_checker(symbols):
stack = []
is_valid = True
par_dict = {'{': '}',
'[': ']',
'(': ')'}
for symbol in symbols:
if symbol in par_dict:
stack.append(symbol)
else:
if stack:
if symbol != par_dict.get(stack.pop()):
is_valid = False
break
else:
is_valid = False
break
return is_valid and stack == []
print(par_checker("{{([][])}()}")) # True
print(par_checker("[{()]")) # False
十进制转换成二进制 ---> 十进制转换成任意进制
对应着: 除以二求余数 --> 除以 n 求余数
def divide_by2(number):
stack = []
while number > 0:
stack.append(number % 2)
number = number // 2
result = ""
while stack:
result += str(stack.pop())
return result
print(divide_by2(15)) # 1111
def divide_by_base(number, base):
stack = []
digits = "0123456789ABCDEF"
while number > 0:
stack.append(number % base)
number = number // base
result = ""
while stack:
result += str(digits[stack.pop()])
return result
print(divide_by_base(15, 16)) # F
print(divide_by_base(233, 8)) # 351
print(divide_by_base(233, 16)) # E9
ADT Queue
队列是一种有次序的数据集合,其特征是新数据项的添加总发生在一端(通常称为“尾rear”端)
而现存数据项的移除总发生在另一端(通常称为“首front”端)
当数据项加入队列,首先出现在队尾,随着队首数据项的移除,它逐渐接近队首。
特点: 先进先出
python代码实现
class Queue:
def __init__(self):
self.items = []
def is_empty(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)
热土豆问题(约瑟夫问题)
传烫手的热土豆,鼓声停的时候,手里有土豆的小孩就要出列。
传说犹太人反叛罗马人,落到困境,约瑟夫和39人决定殉难,坐成一圈儿,报数1~7,报到7的人由旁边杀死,结果约瑟夫给自己安排了个位置,最后活了下来……
def hot_potato(name_list, num):
queue = []
for name in name_list:
queue.insert(0, name)
while len(queue) > 1:
for i in range(num):
queue.insert(0, queue.pop())
print("出列的人是:", queue.pop())
return queue.pop()
print("剩下的人是:", hot_potato(["Bill", "David", "Susan", "Jane", "Kent", "Brad"], 8))
ADT 双端队列 Deque
class Deque:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def add_front(self, item):
self.items.append(item)
def add_rear(self, item):
self.items.insert(0, item)
def remove_front(self):
return self.items.pop()
def remove_rear(self):
return self.items.pop(0)
def size(self):
return len(self.items)
应用: 回文词的判定
radar madam toot
上海自来水来自海上
山东落花生花落东山
def pal_checker(pal_string):
deque = list(pal_string)
still_equal = True
while len(deque) > 1 and still_equal:
first = deque.pop(0)
last = deque.pop()
if first != last:
still_equal = False
return still_equal
print(pal_checker("上海自来水来自海上"))
print(pal_checker("radar"))
print(pal_checker("qjweirjqwir"))
print(pal_checker("你好"))
python 原生的数据类型 列表list
list 是一种数据项按照相对位置存放的数据集 (无序表)
虽然列表的数据结构要求保持数据项的前后相对位置,但这种前后位置的保持,并不要求数据项依次存放在连续的存储空间
当我们从list中移除某个元素的时候, 时间复杂度是O(n)
下面实现另外一种 无序表: 链表
链表:数据项存放位置并没有规则,但如果在数据项之间建立 链接指向,就可以保持其前后相对位置
第一个和最后一个数据项 需要显式标记出来,一个是队首,一个是队尾,后面再无数据了。
链表的实现:节点node
每个节点至少要包含两个信息: 数据项本身(data),以及指向下一个节点的引用信息(next)
需要注意的是next为None的意义是没有节点了,这个很重要。
代码实现:
class Node:
def __init__(self, init_data):
self.data = init_data
self.next = None
def get_data(self):
return self.data
def get_next(self):
return self.next
def set_data(self, new_data):
self.data = new_data
def set_next(self, new_next):
self.next = new_next
链表的实现(单链表):无序表unordered list
可以采用链接节点的方式 构建数据集来实现无序表
链表的第一个和最后一个节点最重要。因为如果想访问到链表中的所有节点,就必须从第一个节点开始沿着链表遍历下去
无序表 必须要有对 第一个节点 的引用信息,设立一个属性head, 保存对第一个节点的引用
空表的hear为None
class UnorderedList:
def __init__(self):
self.head = None
添加新数据项最快捷的位置是表头,整个链表的首位置。
单链表: node 只有包含data ,next
双链表: node 不仅包含data, next, 还包含previous