Python版数据结构与算法

Posted 大聪明Smart

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python版数据结构与算法相关的知识,希望对你有一定的参考价值。

数据结构

引子

未来简史: 数据主义 Dataism

问题的求解: What Why How 基于有穷观点的能行方法

图灵机计算模型

算法和计算复杂性

可计算问题:算法的难易程度

不可计算问题:边界或极限

突破极限:SETI@home、光子计算、智慧众包科研项目

算法分析:计算资源消耗,何为计算资源?存储空间或内存,执行时间。

算法时间度量指标

问题的规模影响算法执行时间

数量级函数 大O表示法 O(n)

例子:T(n) = 5n^2 + 27n +1005 O(n^2)

其他因素: 最好 最差 平均

常见的大O数量级函数 O(1) log(n) O(n) n*log(n) n^2 n^3 2^n

"变位词"问题

abcd dcba

  1. 逐个对比 O(n^2)
  2. 排序对比 O(nlogn)
  3. 暴力穷尽 。。。。
  4. 计数比较 对每个字母出现的次数进行计数 最后对比 O(n) 空间换时间

Python数据类型的性能

让最常用的操作性能最好

pop 最好不要pop(0) 他要把所有的数据都后移一位 时间复杂度很高

线性结构Liner Structure

线性结构是一种有序数据项的集合,其中每个数据项都要唯一的前驱和后继。

数据项的增减方式不同构成了不同的数据结构

栈Stack

一种有次序的数据项集合。在栈中,数据项的加入和移除只发生在同一端。这一端叫栈顶top,另一端叫栈底base。

栈的特性:反转次序

操作

# ADT.py
"""
要掌握思想
栈和队列
"""
# 栈:先进后出的数据结构,栈顶和栈尾。随便选取列表的一端设置位栈顶或栈底。这里把最后一个元素选为栈顶,这种性能会好一点。
# 用列表实现:我们定义列表开始的位置为栈底,末尾为栈顶。
# Stack() 创建一个空栈。它不需要参数,并返回一个空栈。
# push()


class Stack(object):

    def __init__(self):
        self.items = []

    def push(self,item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def peek(self):
        """从栈返回顶部项,但不会删除它。不需要参数,不修改栈。"""
        return len(self.items) - 1

    def isEmpty(self):
        return self.items == []

    def size(self):
        return len(self.items)


if __name__ == '__main__':
    stack = Stack()
    stack.push(1)
    stack.push(2)
    stack.push(3)
    print('栈顶元素下标',stack.peek())
    print(stack.isEmpty())
    print(f'元素个数{stack.size()}')

栈的应用:简单的括号匹配

括号必须正确匹配,

每个开括号“(” 必须对应一个闭括号 “)”;

要正确嵌套。

# 导入栈包
from ADT import Stack


def is_kuohao(s):
    # 创建一个空栈
    stack = Stack()

    for i in s:
        if i == '(':
            # 如果是左括号,入栈
            stack.push(i)
        else:
            # 如果是右括号,则出栈一个左括号,他们俩一对
            if stack.isEmpty():
                # 如果此时栈已空,则直接返回False,因为已经匹配不了了
                return False
            # 不为空才出栈
            stack.pop()

    return stack.isEmpty()


s = input()

print(is_kuohao(s))

栈的应用:混合括号匹配

"""
括号混合存在的情况
"""
# 导入栈包
from ADT import Stack


def match(a, b):
    opens = '{[('
    closes = '}])'
    return opens.index(a)==closes.index(b)


def par_check(s):
    # 创建一个空栈
    stack = Stack()

    for i in s:
        if i in '({[':
            # 如果是左括号,入栈
            stack.push(i)
        else:
            # 如果是右括号,则出栈一个左括号,并检测他们俩是不是一对
            if stack.isEmpty():
                # 如果此时栈已空,则直接返回False,因为已经匹配不了了
                return False
            # 不为空才出栈
            if not match(stack.pop(), i):
                return False

    return stack.isEmpty()


s = input()

print(par_check(s))

栈的应用:进制转换

"""
给定一个十进制数,把他转换成k进制
除k求余法
"""
from ADT import Stack


def digit(base, k):
    arr = '0123456789ABCDEF'
    res = ''
    stack = Stack()
    while base != 0:
        stack.push(arr[base % k])
        base = base // k
    while not stack.isEmpty():
        res += stack.pop()
    return int(res)


print(digit(100, 16))  # 64
print(int('64', 16))  # 100

栈的应用:表达式

中缀表达式:运算符在中间,例如A+B。如果含有其他运算符再要考虑优先级,优先级是人为规定的。

例如A+B*C,为了让计算机具有更强的辨识度,给表达式全部加上括号,这样就无需考虑运算符的优先级而只需考虑括号即可。

例如(A+(B*C)),即全括号表达式。

前缀表达式:为了方便优先级的表示,把运算符放在操作数的前边。

后缀表达式:为了方便优先级的表示,把运算符放在操作数的后边。

中缀表达式前缀表达式后缀表达式
A+B*C+A*BCABC*+

前缀和后缀可以省去括号了。离运算符最近的先操作。计算机里通常勇后缀表达式。

中缀表达式转换位前缀表达式或后缀表达式

(A+(B*C))

看子表达式(B*C)的右括号,运算符一道右括号位置代替他,再删掉左括号得到后缀表达式。

通用转换

从左到右依次扫描,把操作符暂存到一个栈中

if 操作数 直接添加到后缀表达式的末尾

if 左括号 压入opstack栈顶

if 右括号 反复弹出opstack栈顶

操作符加入到输出列表末尾知道碰到左括号

if 操作符 压入opstack栈顶 要比较其与栈顶操作符的优先级 优先级高的在栈顶

"""后缀表达式"""
from ADT import Stack


def hou_ex(ex):
    res = ''
    prec = {'+': 1, '-': 1, '*': 2, '/': 2, '(': 3}
    stack = Stack()
    for s in ex:
        if s not in '()+-*/':
            res += s
            res += ' '
        elif s == '(':
            stack.push(s)
        elif s == ')':
            opt = stack.pop()
            while opt != '(':
                res += opt
                res += ' '
                opt = stack.pop()
        elif s in '+-*/':
            while not stack.isEmpty() and prec[stack.peek()] > prec[s]:
                if stack.peek() == '(':
                    break
                res += stack.pop()
                res += ' '
            stack.push(s)
    while not stack.isEmpty():
        res += stack.pop()
        res += ' '
    return res


ex = list(input().strip().split())
print(hou_ex(ex))
# 11 + 2 * 3

后缀表达式求值

"""后缀表达式求值"""
from ADT import Stack


def compute(x, y, opt):
    if opt == '+':
        return x + y
    elif opt == '-':
        return x - y
    elif opt == '*':
        return x * y
    else:
        return x / y


def hou_value(ex):
    stack = Stack()
    for s in ex:
        if s not in '+-*/':
            stack.push(s)
        else:
            b = int(stack.pop())
            a = int(stack.pop())
            stack.push(compute(a, b, s))
    return stack.pop()


ex = list(input().strip().split())
print(hou_value(ex))
# 11 2 3 * +

队列Queue

队列是一种有次序 的集合,其特征是:新数据项的添加总发生在一端,尾端rear;现存数据项的移除发生在另一端,首端front。

# ADT.py
# 队列:先进先出。队头和队尾。
# 我们定义列表开始位置为队头,末尾为队尾。
class Queue(object):
    def __init__(self):
        self.items = []
        
    def enqueue(self,item):
        self.items.insert(0, item)
        
    def dequeue(self):
        return self.items.pop()
    
    def isEmpty(self):
        return self.items == []
    
    def size(self):
        return len(self.items)


if __name__ == '__main__':

    q = Queue()
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())

双端队列Deque

列表List

以上是关于Python版数据结构与算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法(python版)教程

干货北京大学《数据结构与算法Python版》公开课

Python版数据结构与算法

Python版数据结构与算法

数据结构(python版)—— 1前期知识和综述

数据结构与算法 之 复杂度(python版)