概念

计算机世界著名公式,由瑞士计算机科学家尼克劳斯·威茨(Niklaus Wirth)提出

程序 = 数据结构 + 算法

数据结构

定义

计算机存储 组织数据的方式

分类

  • 物理结构 面向计算机的
    • 顺序存储结构 数据元素在地址连续的存储单元中
    • 链式存储结构 数据元素在任意地址的存储单元中 用指针关联​
  • 逻辑结构 面向问题的
    • 集合
    • 线性
    • 树形
    • 图形

算法

定义

解决特定问题的求解步骤

特性

  • 输入 有零个或多个输入
  • 输出 至少有一个或多个输出​
  • 有穷性
  • 确定性
  • 可行性

算法的时间复杂度和空间复杂度

时间复杂度 计算算法所需要的时间 采用 大O 表示法

  • 常数阶 O(1)

  • 平方阶 O(n 2)

  • 立方阶 O(n 3)

  • 线性阶 O(n)

  • list 的复杂度

    • append 0(1)
    • pop() O(1)
    • pop(i) O(n)
    • sort O(n log n)
    • reverse O(n)
  • dict 的时间复杂度

    • copy O(n)
    • Delete O(1)

    空间复杂度 计算算法所需要的内存

线性表

定义:具有零个或多个数据元素的有限序列

特征

第一个元素没有前驱元素
最后一个元素没有后继元素
其他元素只有一个前驱 和 一个后继

操作 : 插入 删除 查找
分类 : 顺序表 链表

顺序表

定义

在计算机内存中 以一组地址的存储单元 依次存储数据元素的线性结构

插入 删除 最好的时间复杂度O(1) 最坏的时间复杂度 O(n)
查找 时间复杂度为 O(1)

特点:

优点:支持随机访问
缺点:插入和删除需要移动大量元素 会造成空间碎片

适合场景

读取数据的时候 python中的 list tuple

链表

定义

是一种基础数据结构 是一种线性表

分类

单向链表

​ 有俩个域 一个是链接域(下一个节点的地址) 一个是信息域(存放的是数据)
单向循环链表

​ 最后一个节点的指针域指向第一个节点
双向链表

​ 俩个指针域一个元素域

数据结构与算法作用

没有看过数据结构和算法,有时间对问题可能会没有任何思路,不知如何下手去解决:

大部分时间可能解决了问题,可是对程序运行的效率和开销没有意识,性能下降;
有时会借助别人开发的利器暂时解决了问题,可是遇到了性能瓶颈的时候,又不知道该如何进行针对性优化。

按照不同的角度,
数据结构可分为
逻辑结构和物理结构。

逻辑结构:

是指数据对象中数据元素之间的相互关系。
分为四种:
集合结构、线性结构、树形结构和图形结构。

数据元素的存储结构可分为两种:
顺序存储结构 和 链式存储结构。

顺序存储结构:

把数据元素放在地址连续的存储单元中,
数据间的逻辑关系和物理关系一致。如,b

链式存储结构:

把数据元素放在任意的存储单元中,数据间使用指针关联。
数据元素的存储关系不能反映其逻辑关系。如,链表。

算法是解决特定问题求解步骤的描述,
在计算机中表现为指令的有限序列,
并且每条指令表示一个或多个操作。

算法的基本特性:

输入,算法具有零个或多个输入,
输出,至少有一个或多个输出。
有穷性,算法在执行有限步后能够自动结束,不会出现无限循环。
确定性,算法的每一步都具有确定的含义,不会出现二义性。
可行性,算法的每一步都能够通过执行有限次操作完成。

算法复杂度分为时间复杂度和空间复杂度。

时间复杂度是指执行算法所需要的计算工作量(时间)

空间复杂度是指执行这个算法所需要的内存空间

算法的时间复杂度””反映了算法执行的时间长短,它是度量一个算法好坏的重要指标。””
度量一个算法的时间复杂度通常采用大O表示法

时间复杂度的几条基本计算规则:

  1. 基本操作,即只有常数项,认为其时间复杂度为O(1)
  2. 顺序结构,时间复杂度按加法进行计算
  3. 循环结构,时间复杂度按乘法进行计算
  4. 分支结构,时间复杂度取最大值
  5. 判断一个算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略
  6. 在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度
# import time #引入时间模块
# def func():
#     # 时间戳  time.time()
#     start_time = time.time()
#     for i in range(0,1001):       # n*n 循环结构  +9常数项 可以忽略
#         for j in range(0,1001):
#             # s = 1000 - i - j        #顺序结构
#             for s in range(0,1001):
#                 if i ** 2 + j ** 2 + s ** 2 == s ** 2 and i + j + s ==1000 : #二次幂 + - 基本操作   分支结构 if elif
#                     print("i = %d,j = %d ,s =%d" % (i,j,s))  #可以认作基本操作
#
#     end_time = time.time()
#     print("demo 执行时间为:%f" % (end_time-start_time))  #开始到结束用了多长时间
#
# func()




# import time,timeit  #python 内置的性能测试模块
# def func():
#     for i in range(0,1001):
#         for j in range(0,1001):
#             s = 1000 - i - j
#             if i ** 2 + j ** 2 + s ** 2 == s ** 2  :
#                 print("i = %d,j = %d ,s =%d" % (i,j,s))
# if __name__ == '__main__':
#     ss = timeit.Timer("func()","from __main__ import func")
#     print(ss.timeit(5)/5)

构造栈

"""
Stack() 创建一个新的空栈
push(item) 添加一个新的元素item到栈顶
pop() 弹出栈顶元素
peek() 返回栈顶元素
is_empty() 判断栈是否为空
size() 返回栈的元素个数
"""


class Stack():
    """创建一个新的空栈类"""

    def __init__(self):
        """创建一个新的空栈"""
        self.alist = []

    def push(self, item):
        """添加一个新的元素item到栈顶"""
        self.alist.append(item)

    def pop(self):
        """弹出栈顶元素"""
        if self.alist == []:
            return None
        else:
            return self.alist.pop()

    def peek(self):
        """返回栈顶元素"""
        if self.alist == []:
            return None
        else:
            return self.alist[-1]

    def is_empty(self):
        """判断栈是否为空"""
        return self.alist == []

    def size(self):
        """返回栈的元素个数"""
        return len(self.alist)


if __name__ == '__main__':
    s = Stack()
    print(s.is_empty())
    print(s.size())
    s.push(1)
    s.push(2)
    s.push(3)
    s.push(4)
    s.push(5)
    print(s.size())
    print(s.pop())
    print(s.size())
    print(s.is_empty())
    print(s.peek())

进阶写法 数字转二进制

class MyStack:
    def __init__(self):
        self.s = []

    def push(self, x: int) -> None:
        self.s.append(x)

    def pop(self) -> int:	
        return self.s.pop()

    def size(self) -> int:
        return len(self.s)

    def empty(self) -> bool:
        return not bool(self.s)


stack = MyStack()


def transform(num: int) -> str:
    while num != 0:
        remain = num % 2
        num = int(num / 2)
        stack.push(remain)

    s = ""
    while not stack.empty():
        s += str(stack.pop())
    return s


print(transform(13))

构造队列

"""
Queue() 创建一个空的队列
enqueue(item) 往队列中添加一个item元素
dequeue() 从队列头部删除一个元素
is_empty() 判断一个队列是否为空
size() 返回队列的大小

"""


class Queue():

    def __init__(self):
        """创建一个空的队列"""
        self.alist = []

    def enqueue(self, item):
        """往队列中添加一个item元素"""
        self.alist.append(item)

    def dequeue(self):
        """从队列头部删除一个元素"""
        if self.alist == []:
            return None
        else:
            self.alist.pop(0)

    def is_empty(self):
        """判断一个队列是否为空"""
        return self.alist == []

    def size(self):
        """返回队列的大小"""
        return len(self.alist)


if __name__ == '__main__':
    q = Queue()
    print(q.size())
    print(q.is_empty())
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    q.enqueue(4)
    q.enqueue(5)
    q.dequeue()
    q.dequeue()
    q.dequeue()
    print(q.size())
    print(q.is_empty())

进阶写法

class MyQueue:

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

    def push(self, x: int) -> None:
        """
        x: int 申明类型 提高代码健壮性
        -> 返回值 为None
        """
        self.s.append(x)

    def pop(self) -> int:
        return self.s.pop(0)

    def empty(self) -> bool:
        return not bool(self.s)


myq = MyQueue()