python 算法回顾(2) 数据结构及实现

 

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 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值