Python--第二阶段--01.数据结构

本文深入解析数据结构,包括线性表、栈、队列、树形结构等,同时覆盖基础算法如排序和查找,旨在提升编程技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是数据结构

a.数据:存在计算机中能被计算机识别、存储和处理的符号总称。
b.数据元素:record。
c.数据结构:数据元素和数据元素之间的相互关系,或组织数据的形式

2.数据之间的结构关系

a.逻辑结构(对事物抽象–>转化成数学模型)

  1. ☆线性结构:一对一的结构----汽车一辆接着一辆----数据遍历
    特点:有头有尾,有第一个和最后一个,都有唯一的后继,都有唯一的前驱
  2. 树形结构(层次关系):一对多的结构----【二叉树】国家管理机构,省长管n个市长,1个市长管n个县长—计算机文件目录
  3. 图状结构(网状结构):多对多的----高铁线路、航线、地铁线路----网络拓扑图
  4. 其他结构:

b.存储结构

  • 定义:数据在存储器中(寄存器、外存储器、内存储器)的映像
  • 存储结构类型:
    1. 顺序存储:在存储器中放在一片连续的存储空间中----结构紧凑、查找速度快----中间插入时占内存较大、连续存储空间不足时无法存储----列表、元祖、字符串(可以用索引号取值[])
    2. 链式存储:在存储器中分散的存在于存储空间中,前一个元素记录下一个元素的位置----充分灵活利用空间、减少存在数据的移动----关系构建相对困难,遍历查找慢----Python不存在链式存储
    3. 索引存储:在存储数据的同事简历一个附加的索引表,即索引存储结构=数据文件+索引表

3.线性表

a.顺序存储(逻辑结构----线性结构)

  • 定义:在一片存储空间
  • 特点:逻辑相邻,存储位置也相连;存储密度高,方便对数据的遍历;对表的插入和删除等运算效率差
  • eg:列表:增加(append、insert、extend)、修改(list[index]=value、list[start:stop:step]=value)、删除(pop(index)、remove(sub)、del list(index))、查看(in/not in 、index(sub)、)

b.链式存储

  • 定义:即保证分散,又保证关联,每个节点都建立与下一个节点的关联
  • 特点:逻辑上相邻的元素,在存储位置上不一定相同;存储稀疏,不必开辟整块存储空间;对表的插入和删除等运算的效率较高;逻辑结构复杂,不利于遍历。
  • eg:列表的元素是变量的这种形式,就可以看做是链式存储—
a = 1
b = 2
c = [a,b]

4.单链表

  1. 节点node
1 class Node:
2     '''
3         生成节点对象,包含当前数据及下一个节点的引用
4     '''
5     def __init__(self,value,next=None):
6         self.value = value  #要存储的数据
7         self.next = next    #关联的下一个节点
  1. 链表
class Linklist:
    '''
        生成单向的链式的列表,实现数据的增加、修改、删除、查询
    '''

    def __init__(self):
        self.head = Node(None)

    def init_list(self, list_):
        p = self.head
        for i in list_:
            p.next = Node(i)
            p = p.next

    def show(self):
        p = self.head.next  # 第一个有效节点
        while p is not None:
            print(p.value)
            p = p.next  # p向后移动

    # 判断链表为空
    def is_empty(self):
        if self.head.next is None:
            return True
        else:
            return False

    # 清空链表
    def clear(self):
        self.head.next = None

    # 增加节点--尾部插入
    def append_wei(self, value):
        p = self.head
        while p.next is not None:
            p = p.next
        p.next = Node(value)

    # 增加节点--头部插入
    def append_head(self, value):
        node = Node(value)
        node.next = self.head.next  # 链接第二个
        self.head.next = node  # 头链接插入的这个

    # 指定插入位置
    def insert_(self, index, value):
        p = self.head
        for i in range(index):
            if p.next is None:  # 超出最大位置结束循环
                break
            p = p.next

        node = Node(value)
        node.next = p.next
        p.next = node

    # 删除节点
    def remove_(self, value):
        p = self.head
        while p.next and p.next.value != value:
            p = p.next
        if p.next is None:
            raise ValueError("x not in linklist")
        else:
            p.next = p.next.next

    # 获取某个节点的值
    def index_(self, index):
        if index < 0:
            raise IndexError('list index is not exsist')
        p = self.head.next

        for i in range(index):
            if p.next is None:
                raise IndexError('list index is not exsist')
            p = p.next
        return p.value

class Linklist

作业:

  1. 链表的画图整理
  2. 创建两个链表,两个链表中的值均为有序值,将两个链表合并为一个,合并后要求仍为有序值
  3. 《数据结构与算法》

自己做的作业答案:
test1.py

from linklist import *

link1 = Linklist()
link2 = Linklist()
link1.init_list([1, 4, 7])
link2.init_list([2, 5, 8, 10])

# 无序连接
# link1.insert_list(link2)
# link1.show()

# 有序连接第一种方法
# link1.insert_list2(link2)
# link1.show()

# 有序添加单个节点
# link1.insert_2(5)
# link1.show()

# 有序连接--第二种方法建立在有序添加单个节点上的
# link1.insert_list3(link2)
# link1.show()

linklist.py

class Node:
    '''
        生成节点对象,包含当前数据及下一个节点的引用
    '''

    def __init__(self, value, next=None):
        self.value = value  # 要存储的数据
        self.next = next  # 关联的下一个节点


class Linklist:
    '''
        生成单向的链式的列表,实现数据的增加、修改、删除、查询
    '''

    def __init__(self):
        self.head = Node(None)

    def init_list(self, list_):
        p = self.head
        list_.sort()
        for i in list_:
            p.next = Node(i)
            p = p.next

    def show(self):
        p = self.head.next  # 第一个有效节点
        while p is not None:
            print(p.value)
            p = p.next  # p向后移动

    # 判断链表为空
    def is_empty(self):
        if self.head.next is None:
            return True
        else:
            return False

    # 清空链表
    def clear(self):
        self.head.next = None

    # 增加节点--尾部插入
    def append_wei(self, value):
        p = self.head
        while p.next is not None:
            p = p.next
        p.next = Node(value)

    # 增加节点--头部插入
    def append_head(self, value):
        node = Node(value)
        node.next = self.head.next  # 链接第二个
        self.head.next = node  # 头链接插入的这个

    # 指定插入位置
    def insert_(self, index, value):
        p = self.head
        for i in range(index):
            if p.next is None:  # 超出最大位置结束循环
                break
            p = p.next

        node = Node(value)
        node.next = p.next
        p.next = node

    # 删除节点
    def remove_(self, value):
        p = self.head
        while p.next and p.next.value != value:
            p = p.next
        if p.next is None:
            raise ValueError("x not in linklist")
        else:
            p.next = p.next.next

    # 获取某个节点的值
    def index_(self, index):
        if index < 0:
            raise IndexError('list index is not exsist')
        p = self.head.next

        for i in range(index):
            if p.next is None:
                raise IndexError('list index is not exsist')
            p = p.next
        return p.value

    def insert_list(self, linklist1):
        # 无序添加
        p = linklist1.head.next
        while p is not None:
            self.append_wei(p.value)
            p = p.next

    def insert_list2(self, linklist1):
        # 有序添加
        p1 = self.head.next
        p2 = linklist1.head.next
        index = 1
        while p2 is not None:
            if p1.next is None:
                self.append_wei(p2.value)
                index += 1
                p2 = p2.next
            elif p2.value >= p1.value and p2.value<p1.next.value:
                self.insert_(index, p2.value)
                index += 1
                p2 = p2.next
                p1 = p1.next
            elif p2.value >= p1.value and p2.value >p1.next.value:
                index += 1
                p1 = p1.next
            else:
                self.insert_(index-1, p2.value)
                p2 = p2.next
                index += 1

# 修改insert函数似的实现两个单链表合并为按顺序排列的单链表
    # 按序列增加
    def insert_2(self,value):
        p = self.head
        while p.next is not None and p.next.value < value:
            p = p.next
        node = Node(value)
        node.next = p.next
        p.next = node

    # 按序列增加linklist
    def insert_list3(self,linklist):
        p = linklist.head.next
        while p is not None:
            value = p.value
            self.insert_2(value)
            p = p.next

老师的答案

5.栈:

  • 定义:先入后出,后进先出。像羽毛球桶一样,先放进去的羽毛球,只能后取出,后放入的羽毛球只能先取出

a.栈的顺序存储(列表的结尾作为栈顶,开头作为栈底):

Stack.py

# 自定义异常
class StackError(Exception):
    pass

# 顺序栈类
class SStack:
    def __init__(self):
        self.list_ = []  # 构建一个栈的模型  先入后出,后入先出

    # 入栈
    def inner(self, value):
        self.list_.append(value)
    # 出栈
    def outer(self):
        # self.list_.pop()
        if self.is_empty():
            raise StackError('Stack is empty')
        return self.list_.pop()

    # 判断列表是否为空
    def is_empty(self):
        return self.list_ == []
        # if self.list_ is None:
        #     return True
        # else:
        #     return False

    def top(self):
        if self.is_empty():
            raise  StackError('Stack is empty')
        return self.list_[-1]
if __name__ == '__main__':
    st = SStack()  # 初始化栈
    st.inner('11')
    st.inner('22')
    st.inner('33')
    while not st.is_empty():
        print(st.outer())

逆波兰表达式

# 逆波兰表达式
# 1 3 + 4 - p
# 当输入数字入栈,遇到符号出就近的两个元素运算后入栈,p后打印结果

# 自定义异常

from sstack import *

st = SStack()

while True:
    exp = input()
    tmp = exp.split(' ') #按空格分裂为列表
    print(tmp)
    for i in tmp:
        if i not in ['+','-','*','/','p']:
            st.inner(float(i))
        elif i == '+':
            y = st.outer()
            x = st.outer()
            st.inner(x + y)
        elif i == '-':
            y = st.outer()
            x = st.outer()
            st.inner(x - y)
        elif i == '*':
            y = st.outer()
            x = st.outer()
            st.inner(x * y)
        elif i == '/':
            y = st.outer()
            x = st.outer()
            st.inner(x / y)
        elif i == 'p':
            print(st.top())
        else:
            print('输入错误')

b.栈的链式存储(节点的将头作为栈顶,结尾作为栈底):

栈的单链表代码

"""
    思路分析:
    1.源于链表结构
    2.封装栈的操作方法,入栈和出栈,栈空,获取栈顶元素
    3.确定栈顶位置,用链表的开头作为栈顶,不需要每次遍历
"""
class StackError(Exception):
    pass

#节点类
class Node:
    def __init__(self,value,next = None):
        self.value = value
        self.next = next

# 链式栈操作
class LinkList_Stack:
    def __init__(self):
        # self.head = Node()
        # 标记栈顶位置
        self._top = None

    def is_empty(self):
        if self._top == None:
            return True
        else:
            return False

    def inner(self,value):
        # node = Node(value)
        # node.next = self._top
        # self._top = node
        self._top = Node(value,self._top)

    def outer(self):
        if self._top == None:
            raise StackError('Stack is empty')
        value = self._top.value
        self._top = self._top.next
        return value

    def top(self):
        if self._top == None:
            raise StackError('Stack is empty')
        return self._top.value
        pass


if __name__ == '__main__':
    st = LinkList_Stack()
    st.inner('11')
    st.inner('22')
    st.inner('33')
    # while True:
    print(st.outer())
    print(st.is_empty())

6.队列

  • 定义(先进先出,后进后出):

    队列是限制在两端进行插入操作和删除操作的线性表,允许进行存入操作的一端称为“队尾”,允许进行删除操作的一段为“队头”。(排队买饭、排号叫号系统)

  • 特点:

    队列只能在队头和队尾进行数据操作
      队列模型具有先进先出或者后进后出的规律

队列的顺序存储(列表的尾作为队尾,列表的头作为队头)

squeue.py

'''

    思路分析:
    1.基于列表完成数据存储
    2.通过封装规定数据操作
'''
class QueueError(Exception):
    pass

class Squeue:

    def __init__(self):
        self._list = []
     # 判断是否为空
    def is_empty(self):
        return self._list == []
    # 入队
    def inner(self,value):
        self._list.append(value)
    # 出队
    def outer(self):
        if self.is_empty():
            raise QueueError('没有元素了!')
        else:
            return self._list.pop(0)
    def show(self):
        print(self._list)


if __name__ == '__main__':
    st = Squeue()  # 初始化栈
    # st.inner('12')
    # st.inner('13')
    # st.inner('14')
    # st.inner('15')
    # st.show()
    # while not st.is_empty():
    #     print(st.outer())

    for i in range(10):
        st.inner(i)
    st.show()
    while not st.is_empty():
        print(st.outer())

队列的链式存储

link_queue.py

"""
    链式队列
    重点代码

    思路:
    1.基于链表构建队列模型
    2.链表的开端作为队头,链表的结尾位置作为队尾
    3.单独定义队尾标记,避免每次插入数据遍历

"""
# 自定义异常
class QueueError(Exception):
    pass
# 节点类
class Node:
    def __init__(self, value,next = None):
        self.value = value
        self.next = next


# 队列操作
class LQueue:
    def __init__(self):
        # 定义队头和队尾的属性变量
        self.front = self.rear = Node(None)

    def is_empty(self):
        return  self.front == self.rear


    def inner(self,value):
        self.rear.next = Node(value)
        self.rear =self.rear.next

    def outer(self):
        if self.front == self.rear:
            raise QueueError('Queue is empty')
        self.front = self.front.next
        return self.front.value

if __name__ == "__main__":
    lq = LQueue()
    lq.inner(10)
    lq.inner(20)
    lq.inner(30)
    print(lq.outer())
    print(lq.outer())
    print(lq.outer())

作业:

  1. 重点代码复习
  2. 编写一个接口程序,获取一段文字,判断文字中括号是否匹配正确,如果正确则打印正确,不正确则指出出错的地方。

自己的作业代码:

from linklist_stack import *
str = '((sdfasdf【adfas)】[adfasdf()]{}'
# list1 = []
# for i in str:
#     list1.append(i)
# print(list1)
dict_L = {
    ')':'(',
']':'[',
'}':'{',
')':'(',
'】': '【'
}
LStack = LinkList_Stack()
LStack_count = LinkList_Stack()
count = 1
count_error = 0
for i in str:
    if i in ['(','[','{','(','【','{']:
        LStack.inner(i)
        LStack_count.inner(count)

    elif i in [')',']','}',')','】','}']:
        p = LStack.outer()
        p_count = LStack_count.outer()
        if dict_L[i] != p:
            print('括号错误,在第%s和%s个字符处'%(count,p_count))
            count_error += 1
    count += 1
if LStack.is_empty() and count_error == 0:
    print('恭喜你,没有错误')
else:
    print('有错误')
    while not LStack_count.is_empty():
        print(LStack_count.outer(),'字符处有问题')

7.非线性模型

树形结构

  • 定义:有且只有一个特定的根节点;其余节点互不相交(子节点不能有两个上级节点,同一个人不能归于两个不同的部门)。

  • 基本概念:

    • 根:无父节点
    • 子树:
    • 度:
    • 叶子:度为0的就是叶子,不同叶子可能不是同一层,无子节点
    • 子节点:
    • 父节点:parant
    • 兄弟节点:
    • 路径:从上到下的路径,不能往回走。
    • 节点的层数(高度或深度):根为第一层
    • 森林:多棵树的集合

二叉树

  • 定义:树形中,每个子节点最多只有2个

  • 特征:

    1. 二叉树第i层上的节点,最多有2的i-1次方个;
    2. 深度k的二叉树最多有2的k次-1个节点;
    3. 在任意一颗二叉树中,树叶的数目比度数为2的节点的数目多一;
    4. 满二叉树:深度为k(k>=1)时有2的k次方-1个节点的二叉树;
    5. 完全二叉树:只有最下面两层的度数小于2个的节点,且最下面一层的叶节点集中在最左边的若干位置上。
  • 形式(严格区分左右节点):

    • 空二叉树:没节点
    • 只有根节点:
    • 只有左孩子:
    • 只有右孩子:
  • 遍历方法:每当遇到一个节点时当做根节点,递归思想。

    • 先序遍历(根左右):
    • 中序遍历(左根右):
    • 后序遍历(左右根):
    • 层次遍历:
      在这里插入图片描述
  • 递归思想:

    • 定义:在函数内部直接或间接的调用自身的函数。
    • 包含两个阶段:
      • 递推阶段:逐层调用,必须设定终止条件,终止条件写在调用自身之前。
      • 回归阶段:按递归有终止条件。
    • 优点:递归可以把问题简化,让思路清晰,代码简洁。
    • 缺点:递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果。
  • 二叉树Python遍历:
    在这里插入图片描述

二叉树的遍历:列表和节点

"""
    列表二叉树(完全二叉树或者满二叉树的时候可以考虑用,其他时候不用)
"""

['A',
 ['B',None,None],
 ['C',['D',None,None],['E',None,None]]
]


'''
思路说明:
1.使用链式存储,一个Node节点表示一个树的节点
2.节点考虑使用两个属性变量分别表示左链接和右链接
'''

# 二叉树节点类
class Node:
    def __init__(self,value,left=None,right=None):
        self.value = value
        self.left = left
        self.right = right

class Bitree:
    def __init__(self,root):
        self.root = root

    # 先序遍历
    def preOrder(self,node):
        if node is None:  #终止条件
            return
        print(node.value,end = ' ')
        self.preOrder(node.left)
        self.preOrder(node.right)

    # 中序遍历
    def inOrder(self,node):
        if node is None:  #终止条件
            return
        self.inOrder(node.left)
        print(node.value,end = ' ')
        self.inOrder(node.right)

    # 中序遍历
    def behOrder(self,node):
        if node is None:  #终止条件
            return
        self.behOrder(node.left)
        self.behOrder(node.right)
        print(node.value,end = ' ')

if __name__ == '__main__':
    # 后序遍历 :B F G D I H E C A
    b = Node('B')
    f = Node('F')
    g = Node('G')
    d = Node('D',f,g)
    i = Node('I')
    h = Node('H')
    e = Node('E',i,h)
    c = Node('C',d,e)
    a = Node('A',b,c) #根节点
    
    # 将a作为遍历的起始位置
    bt = Bitree(a)
    bt.preOrder(bt.root)
    print('=='*20)
    bt.inOrder(bt.root)
    print('=='*20)
    bt.behOrder(bt.root)

8. 基础算法

  • 定义:

  • 算法的特性:

    • 有穷性——算法执行的步骤是有限的
    • 确定性——每个计算步骤无二义性
    • 可行性——每个计算步骤能够在有限的时间内完成
    • 输入,输出——存在数据的输入和输出
  • 评价算法好坏的方法

    • 正确性:运行正确是一个算法的前提
    • 可读性:容易理解、容易变成和调试、容易维护
    • 健壮性:考虑情况全面,不容易出现运行错误
    • 时间效率高:算法消耗的时间少
    • 存储量低:占用较少的存储空间
  • 时间效率的计算方法:

    • 所有运算语句执行次数加和
    • 如果获得的结果是常量则时间复杂度为1
    • 如果得到的结果中存在变量n则取n的最高次幂作为时间复杂度

9.排序

冒泡排序

描述:两两相比交换位置,每轮选出最大的值,每轮最大值不参与下一次的比较。
冒泡排序
冒泡排序代码:

def bubble(list_):
    # 外层表示比较多少轮
    n = len(list_)
    for i in range(n - 1):
        for j in range(n - 1 - i):
            if list_[j] > list_[j + 1]:
                list_[j], list_[j + 1] = list_[j + 1], list_[j]

选择排序

描述:
选择排序
选择排序代码:

# 选择排序:假定一个最小的,然后后面的相比,更小的一个和假定的最小的进行交换位置
# 我自己做的
def choice_Sort(list_, count=0):
    if count == len(list_):
        print('转换完成')
    else:
        temp = [list_[count], count]
        for i in range(count, len(list_)):
            if list_[i] <= temp[0]:
                temp = [list_[i], i]
        list_[count], list_[temp[1]] = temp[0], list_[count]
        choice_Sort(list_, count + 1)


# 老师做的
def select(list_):
    # 每轮选出一个最小值,需要len(list_)-1轮
    for i in range(len(list_) - 1):
        min = i  # 假设list_[i]为最小值
        for j in range(i + 1, len(list_)):
            if list_[min] > list_[j]:
                min = j  # 擂主换人
            # 进行交换,将最小值换到应该在的位置
            if min != i:
                list_[i], list_[min] = list_[min], list_[i]

插入排序

插入排序

# 插入排序:
def insert_Sort(list_):
    for i in range(len(list_)):
        for j in range(i, len(list_)):
            if list_[i] > list_[j]:
                list_[i], list_[j] = list_[j], list_[i]

快速排序

快速排序
快速排序代码:

# 快速排序:
# 自己写的


# 老师写的
def sub_Sort(list_, low, high):
    # 选定基准
    x = list_[low]
    # low向后,high向前
    while low < high:
        while list_[high] >= x and high > low:
            high -= 1
        list_[low] = list_[high]
        while list_[low] < x and low < high:
            low += 1
        list_[high] = list_[low]
    list_[low] = x
    return low


def quick_Sort(list_,low,high):
    if low < high:
        key = sub_Sort(list_, low, high)
        quick_Sort(list_,low,key-1)
        quick_Sort(list_,key+1,high)

10.查找

二分查找

"""
    二分查找方法训练
"""

# list_为有序数列,key为要查找的关键值,返回key在数列中的索引号

def search(list_, key):
    low,high = 0 ,len(list_)-1
    while low < high:
        mid = (low + high) // 2
        if list_[mid] < key:
            low = mid+1
        elif list_[mid] > key:
            high = mid-1
        else:
            return mid


l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print('KEY INDEX:',search(l, 11))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值