首页 > 编程语言 >Python数据结构与算法——数据结构(链表、哈希表、树)

Python数据结构与算法——数据结构(链表、哈希表、树)

时间:2024-03-31 22:59:20浏览次数:29  
标签:__ Python self 链表 哈希 数据结构 节点 def

目录

链表

    链表介绍

    创建和遍历链表

    链表节点插入和删除

    双链表

    链表总结——复杂度分析

哈希表(散列表)

哈希表介绍

哈希冲突

哈希表实现

哈希表应用

树的示例——模拟文件系统

二叉树

二叉树的链式存储

 二叉树的遍历

二叉搜索树

插入

查询

删除

AVL树

旋转

插入


链表

    链表介绍

        链表是由一系列节点组成的元素集合,每个节点包含两部分,数据域item和指向下一个节点的指针next。通过节点之间的相互连接,最终串联成一个链表。

节点定义:

class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None

    创建和遍历链表

        头插法/尾插法

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

# 创建链表(头插法)
def crweate_linklist_head(li):
    head = Node(li[0])
    for element in li[1:]:
        node = Node(element)
        node.next = head
        head = node
    return head

# 创建链表(尾插法)
def crweate_linklist_tail(li):
    head = Node(li[0])
    tail = head
    for element in li[1:]:
        node = Node(element)
        tail.next = node
        tail = node
    return head

# 打印链表(遍历)
def print_linklist(lk):
    while lk:
        print(lk.item, end=',')
        lk = lk.next
    print()

    链表节点插入和删除

        插入是创建一个节点,将该节点指向插入位置的下一个节点,上一个节点指向该节点。

        删除是将上一个节点的next指向下一个节点。

    双链表

        双链表每个节点有两个指针:一个指向后一个节点,另一个指向前一个节点。

节点定义:

class Node(object):
    def __init__(self, item=None):
        self.item = item
        self.next = None
        self.prior = None

    链表总结——复杂度分析

  •         按元素值查找:O(n)
  •         按下标查找:O(n)
  •         在某元素后插入:O(1)
  •         删除某元素:O(1)

链表在插入和删除的操作上明显快于顺序表

链表的内存可以更灵活分配

链表这种链式存储的数据结构对树和图的结构有很大启发性

哈希表(散列表)

哈希表介绍

介绍:哈希表是一个通过哈希函数来计算数据存储位置的数据结构,通常支持如下操作:

  • insert(key, value):插入键值对(key, value)
  • get(key):如果存在键为key的键值对,返回其valve,否则返回空值
  • delete(key):删除键为key的键值对

哈希表是一种线性表的存储结构。哈希表由一个直接寻址表和一个哈希函数构成。哈希函数h(k)将元素关键字k作为自变量,返回元素的存储下标。

哈希冲突

哈希冲突:由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因此对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况。

1.开放寻址法:如果哈希函数返回的位置已经有值,则可以向后探查新的位置来存储这个值。

  • 线性探查:如果位置i被占用,则探查i+1, i+2......
  • 二次探查:如果位置i被占用,则探查i+1^2, i-1^2, i+2^2, i-2^2,......
  • 二度哈希:有n个哈希函数,当使用第一个哈希函数h1发生冲突时,则尝试使用h2,h3......

2.拉链法:哈希表每个位置都连接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后。

常见哈希函数:

  • 除法哈希法:h(k) = k % m
  • 乘法哈希法:h(k) = floor(m*(A*key%1))
  • 全域哈希法:h_{a,b}(k) = ((a*key + b) mod p)mod m  a,b = 1, 2, ...,p-1

哈希表实现

class LinkList:
    # 定义节点类
    class Node:
        def __init__(self, item=None):
            self.item = item  # 节点的数据项
            self.next = None  # 指向下一个节点的指针

    # 定义迭代器类
    class LinkListIterator:
        def __init__(self, node):
            self.node = node  # 当前节点

        def __next__(self):
            if self.node:  # 如果当前节点存在
                cur_node = self.node  # 保存当前节点
                self.node = cur_node.next  # 将当前节点指向下一个节点
                return cur_node.item  # 返回当前节点的数据项
            else:
                raise StopIteration  # 当遍历结束时抛出StopIteration异常

        def __iter__(self):
            return self  # 返回迭代器自身

    # 初始化链表
    def __init__(self, iterable=None):
        self.head = None  # 头节点
        self.tail = None  # 尾节点
        if iterable:
            self.extend(iterable)  # 如果传入可迭代对象,则调用extend方法进行扩展

    # 在链表尾部添加节点
    def append(self, obj):
        s = LinkList.Node(obj)  # 创建新节点
        if not self.head:  # 如果链表为空
            self.head = s  # 新节点作为头节点
            self.tail = s  # 新节点作为尾节点
        else:
            self.tail.next = s  # 将新节点连接到当前尾节点后
            self.tail = s  # 更新尾节点为新节点

    # 扩展链表
    def extend(self, iterable):
        for obj in iterable:
            self.append(obj)  # 逐个添加可迭代对象中的元素

    # 查找元素是否在链表中
    def find(self, obj):
        for n in self:  # 遍历链表中的每个节点
            if n == obj:  # 如果找到目标元素
                return True  # 返回True
        else:
            return False  # 找不到目标元素时返回False

    # 返回链表的迭代器
    def __iter__(self):
        return self.LinkListIterator(self.head)

    # 返回链表的字符串表示
    def __repr__(self):
        return "<<" + ", ".join(map(str, self)) + ">>"


# 类似于集合的结构
class HashTable:
    def __init__(self, size = 101):
        self.size = size
        self.T = [LinkList() for _ in range(self.size)]  # 创建域

    # 哈希函数
    def h(self, k):
        return k % self.size

    # 插入
    def insert(self, k):
        i = self.h(k)
        if self.find(k):  # 如果有
            print("Duplicated Insert.")
        else:
            self.T[i].append(k)

    # 查找
    def find(self, k):
        i = self.h(k)
        return self.T[i].find(k)


ht = HashTable()

for i in range(200):
    ht.insert(i)

# print(",".join(map(str, ht.T)))
print(ht.find(203))

哈希表应用

        python的字典,集合都是哈希表

        md5算法

介绍:树是一种数据结构

  • 树是一种可以递归定义的数据结构
  • 树是由n个结点组成的集合
  • 如果n=0,那这是一棵空树
  • 如果n>0,那存在一个结点作为树的根结点,其他结点可以分为m个集合,每个集合本身又是一棵树

一些概念:

  • 根结点、叶子结点
  • 树的深度/高度
  • 树的度
  • 孩子结点、父结点
  • 子树

树的示例——模拟文件系统

# 节点
class Node:
    def __init__(self, name, type = 'dir'):
        self.name = name
        self.type = type  # 'dir' or 'file'
        self.children = []  # 存儿子节点
        self.parent = None  # 指向父节点

    def __repr__(self):
        return self.name

# 树类
class FileSystemTree:
    def __init__(self):
        self.root = Node('/')
        self.now = self.root
    
    # 创建目录
    def mkdir(self, name):
        # name得是一个目录,以'/'结尾
        if name[-1] != '/':
            name += '/'
        node = Node(name)
        self.now.children.append(node)
        node.parent = self.now

    # 展示所有目录
    def ls(self):
        return self.now.children

    # 切换目录
    def cd(self, name):
        # 只支持往下走一层
        if name[-1] != '/':
            name += '/'
        if name == '../':
            self.now = self.now.parent
            return
        for child in self.now.children:
            if child.name == name:
                self.now = child
                return
        raise ValueError("invalid dir")

tree = FileSystemTree()
tree.mkdir("var/")
tree.mkdir("bin/")
tree.mkdir("usr/")

print(tree.ls())

tree.cd("bin")
tree.mkdir("python")

print(tree.ls())

tree.cd("../")
print(tree.ls())

二叉树

二叉树就是度不超过2的树

  • 每个结点最多有两个孩子结点
  • 两个孩子结点被区分为左孩子结点和右孩子结点

完全二叉树

  • 满二叉树:一个二叉树,如果一个层的节点数都达到最大值,则这个二叉树就是满二叉树
  • 完全二叉树:叶子节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

二叉树的存储方式(表示方式)

  • 链式存储方式
  • 顺序存储方式(堆排序用这个)——用列表来存
  • 父结点和左孩子结点的编号下标的关系

                0-1 1-3 2-5 3-7 4-9

                i -> 2i+1

  • 父结点和右孩子结点的编号下标的关系

                0-2 1-4 2-6 3-8 4-10

                i -> 2i+2

之前学过线性存储,这里是链式存储

二叉树的链式存储

将二叉树的节点定义为一个对象,节点之间通过类似链表的链接方式来连接。

节点定义:

class BiTreeNode:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None

 二叉树的遍历

二叉树的遍历方式:

  • 前序遍历:如果不空,先访问根,再访问左子树,最后访问右子树。
  • 中序遍历:如果不空,先访问左子树,再访问根,最后访问右子树。
  • 后序遍历:如果不空,先访问左子树,再访问右子树,最后访问根。
  • 层次遍历:一层一层访问。
# 前序遍历
def pre_order(root):
    if root:
        print(root.data, end=',')
        pre_order(root.lchild)
        pre_order(root.rchild)

# 中序遍历
def in_order(root):
    if root:
        in_order(root.lchild)
        print(root.data, end=',')
        in_order(root.rchild)

# 后序遍历
def post_order(root):
    if root:
        in_order(root.lchild)
        in_order(root.rchild)
        print(root.data, end=",")

# 层次遍历

from compileall import queue
def level_order():
    queue = deque()
    queue.append(root)
    while len(queue) > 0:  # 只要队不空
        node = queue.popleft()
        print(node.data, end=',')
        if node.lchild:
            queue.append(node.lchild)
        if node.rchild:
            queue.append(node.rchild)

二叉搜索树

是一颗二叉树,并且满足左子树的根比根小,右子树的根比根大。

二叉搜索树的操作:查询、插入、删除

插入

pass

查询

pass

删除

pass

AVL树

旋转

pass

插入

pass

代码自己手动敲一遍理解更深哦!

标签:__,Python,self,链表,哈希,数据结构,节点,def
From: https://blog.csdn.net/qq_63043783/article/details/137195523

相关文章

  • 【数据结构】线性表-单链表
    编程语言:C++前言:节点:节点是链表的一个基本单元,包含两部分——数据域和指针域,数据域用于存储数据,指针域存储下一个节点的地址,形成链结。什么是单链表:n个节点链结成一个链表,即为线性表(a1,a2,a3……)的链式存储结构,每个节点只包含一个指针域的链表叫做单链表。链表组成:头节点、......
  • python str.format高级用法
    在Python2中,str.format()函数可以使用一些高级的格式化选项,下面是一些常用的高级用法:1.格式化数字可以使用格式化选项来控制数字的显示方式,例如:#将数字格式化为带千位分隔符的字符串n=1234567s="{:,}".format(n)print(s)#输出:1,234,567#将数字格式化为指定......
  • Python基础语法(四)
    目录一.while循环的基础语句二.while循环案例三.while循环的嵌套四.while循环嵌套的案例一.while循环的基础语句1.while的条件需得到布尔类型,True表示继续循环,False表示结束循环。2.需要设置循环终止的条件,如i+=1配合i<100,就能确保100次后停止,否则将无限循环。3......
  • Python与供应链-2预测误差及指数平滑需求预测模型
    主要介绍预测误差和指数平滑模型的相关理论,然后再通过Python的statsmodels封装的指数平滑函数预测需求。1预测误差预测误差是指预测结果与预测对象发展变化的真实结果之间的差距。这种误差分为绝对误差和相对误差。绝对误差是预测值与实际观测值的绝对差距,而相对误差则是这种......
  • python动态加载(三)
    classTestInstance:def__init__(self):#初始化库字典,存放找到的库self.lib=Proxy()#使用一个代理对象来模拟层级结构#加载库,这里只是模拟,实际中需要导入库模块self._load_libs()def_load_libs(self):#加载p......
  • vscode远程连接docker容器打断点调试python项目
    vscode远程连接服务器docker容器前提:本地和远程都安装docker插件。1.安装完docker插件后点击插件图标2.如果登录的账号没有docker权限的会会报权限不足,使用以下命令把用户加到docker权限组中sudogpasswd-a<当前登陆用户名>docker#从用户组中删除:sudogpasswd-d<当前......
  • 理解 Python 编程中 *args 与 **kwargs 的妙用
    文章目录一、形式参数与实际参数二、*args与**kwargs三、总结......
  • Python大数据为啥一定要用Numpy Array,靠着这份900多页的PDF面试整理
    1.内存占用更小适当地使用Numpy数组替代List,你能让你的内存占用降低20倍。对于Python原生的List列表,由于每次新增对象,都需要8个字节来引用新对象,新的对象本身占28个字节(以整数为例)。所以列表list的大小可以用以下公式计算:64+8*len(lst)+len(lst)*28字节而使......
  • python+opecv打开电脑本地相机并切换不同分辨率
    python+opecv打开电脑本地相机并切换不同分辨率一、实现业务场景:1、电脑摄像头功能要切换相机不同分辨率二、安装、前置条件1、电脑支持摄像头并驱动正常2、python安装opencv并使用国内源【豆瓣】pipinstall-ihttps://pypi.douban.com/simpleopencv-python三、......
  • 数据结构(六)——图的遍历
    6.3图的遍历6.3.1图的广度优先遍历⼴度优先遍历(Breadth-First-Search,BFS)要点:1.找到与⼀个顶点相邻的所有顶点2.标记哪些顶点被访问过3.需要⼀个辅助队FirstNeighbor(G,x):求图G中顶点x的第⼀个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1。Next......