1、Python 基本数据结构

文章目录

    • 一、线性数据结构
      • 1. 线性数据结构的特点
      • 2. 线性数据结构分类
    • 二、链表(LinkedList)
      • 1、链表简介
      • 2、单向链表的基本操作(增删改查)
      • 3、使用类来模拟链表
    • 三、栈(Stack)
      • 1、栈的特点
      • 2、栈的基本操作
      • 3、使用列表来模拟栈
    • 四、队列(Queue)
      • 1、队列的特点
      • 2、队列的基本操作
      • 3、使用列表来模拟队列
    • 五、双端队列(Deque)
      • 1. 双端队列的特点
      • 2. 使用列表来模拟双端队列
    • 六、哈希表(HashTable)
      • 1、哈希表的特点
      • 2、哈希函数
    • 六、参考资料


一、线性数据结构

数据结构:数据的组织、 管理和存储格式, 其使用目的是为了高效地访问和修改数据

1. 线性数据结构的特点

  • 数据项之间只存在先后的次序关系,新的数据项加入到数据集中时,只会加入到原有某个数据项之前或之后
  • 线性结构总有两端:左右端、前后端、顶端底端等,但两端的称呼并不是关键,不同线性结构的关键区别在于数据项增减的方式,有的结构只允许数据项从一端添加,而有的结构则允许数据项从两端移除

2. 线性数据结构分类

  • 线性结构:数组(Array,类似 Python 中的 List)和链表(LinkedList)
  • 线性结构衍生品:栈(stack)、队列(queue)、双端队列(deque)、哈希表
    1、Python 基本数据结构_第1张图片

二、链表(LinkedList)

1、链表简介

  • 概念:

    • 链表是一种在物理上非连续、 非顺序的数据结构,由若干节点(node) 所组成
    • 链表的第 1 个节点被称为头节点, 最后 1 个节点被称为尾节点, 尾节点的 next 指针指向
  • 分类:

    • 单向链表:每一个节点包含两部分, 一部分是存放数据的变量 data, 另一部分是指向下一个节点的指针 next
      1、Python 基本数据结构_第2张图片

    • 双向链表:每一个节点除了拥有 datanext 指针, 还拥有指向前置节点的 prev 指针
      在这里插入图片描述

  • 数组和链表对比:

    • 数组是由有限个相同类型的变量所组成的有序集合, 它的物理存储方式是顺序存储, 访问方式是随机访问; 利用下标查找数组元素的时间复杂度是 O(1), 中间插入、 删除数组元素的时间复杂度是 O(n)
    • 链表是一种链式数据结构, 由若干节点组成, 每个节点包含指向下一节点的指针,它的物理存储方式是随机存储(每一个节点分布在内存的不同位置, 依靠 next 指针关联起来), 访问方式是顺序访问;查找链表节点的时间复杂度是 O(n), 中间插入、 删除节点的时间复杂度是 O(1)
      1、Python 基本数据结构_第3张图片

2、单向链表的基本操作(增删改查)

  • 增(末尾、头部、中间):

    • 尾部插入:把最后一个节点的 next 指针指向新插入的节点,新插入节点的 next 指针指向空
      1、Python 基本数据结构_第4张图片
    • 头部插入:把新节点的 next 指针指向原先的头节点,把新节点变为链表的头节点
      1、Python 基本数据结构_第5张图片
    • 中间插入:把新节点的 next 指针,指向插入位置的节点,插入位置前置节点的 next 指针, 指向新节点
      1、Python 基本数据结构_第6张图片
  • 删(末尾、头部、中间):

    • 尾部删除:把倒数第 2 个节点的 next 指针指向空
      1、Python 基本数据结构_第7张图片
    • 头部删除:把链表的头节点设为原先头节点的 next 指针
      1、Python 基本数据结构_第8张图片
    • 中间删除:把要删除节点的前置节点的 next 指针,指向要删除元素的下一个节点
      1、Python 基本数据结构_第9张图片
  • 改:查找后替换成新数据即可
    1、Python 基本数据结构_第10张图片

  • 查:只能从头节点开始向后一个一个节点逐一查找,eg: 查找从头节点开始的第 3 个节点

    • 将查找的指针定位到头节点
    • 根据头节点的 next 指针, 定位到第 2 个节点
    • 根据第 2 个节点的 next 指针, 定位到第 3 个节点, 查找完毕
      1、Python 基本数据结构_第11张图片

3、使用类来模拟链表

  • 假设链表要实现如下功能:
    1、Python 基本数据结构_第12张图片
  • 代码实践
# 节点类
class Node(object):
    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


# 链表类
class LinkedList(object):
    def __init__(self):
        self.head = None  # 初始化链表头,指向空

    def is_empty(self):
        return self.head is None

    # 从链表头部插入节点
    def add(self, item):
        temp = Node(item)
        temp.set_next(self.head)  # 把新节点的 next 指针指向原先的头节点
        self.head = temp  # 把新节点(node class object)变为链表的头节点

    # 从链表头开始遍历链表,用变量累加经过的节点个数
    def size(self):
        current = self.head
        count = 0
        while current:
            count += 1
            current = current.get_next()
        return count

    # 判断某元素是否在链表中
    def search(self, item):
        current = self.head
        found = False
        while current and not found:
            if current.get_data() == item:
                found = True
            else:
                current = current.get_next()
        return found

    # 移除链表中的某个元素
    def remove(self, item):
        current = self.head
        previous = None  # 用于维护前一个节点的引用
        found = False
        while not found:
            if current.get_data() == item:
                found = True
            else:
                previous = current
                current = current.get_next()
        if previous:
            previous.set_next(current.get_next())  # 中间/尾部删除:把要删除节点的前置节点的 next 指针,指向要删除元素的下一个节点
        else:
            self.head = current.get_next()  # 头部删除:把链表的头节点设为原先头节点的 next 指针


if __name__ == "__main__":
    mylist = LinkedList()

    mylist.add(31)
    mylist.add(77)
    mylist.add(17)
    mylist.add(93)
    mylist.add(26)
    mylist.add(54)

    print(mylist.size())       # 6
    print(mylist.search(93))   # True
    print(mylist.search(100))  # False

    mylist.add(100)
    print(mylist.search(100))  # True
    print(mylist.size())       # 7

    mylist.remove(54)
    print(mylist.size())       # 6
    mylist.remove(93)
    print(mylist.size())       # 5
    mylist.remove(31)
    print(mylist.size())       # 4
    print(mylist.search(93))   # False


三、栈(Stack)

1、栈的特点

  • 栈是一种线性逻辑结构, 可以用数组或链表实现,python 中的 list 很好的实现了栈的功能, append 方法相当于入栈,pop 方法相当于出栈
  • 在栈中,数据项的加入和移除都仅发生在栈顶,遵循后进先出特性:Last in First out(LIFO),eg: word 中的 undo 操作,最先撤销的是最近的操作
  • 通常用于对历史的回溯,具有反转次序的特性(进栈和出栈的次序正好相反)
  • 在经典的操作系统中,栈顶为低地址,压栈的操作使得栈顶的地址减小,弹出操作使得栈顶地址增大,内存生长方向(小端模式-高位字节->低位字节)
    1、Python 基本数据结构_第13张图片

2、栈的基本操作

  • 包括入栈和出栈,只会影响到最后一个元素,不涉及其他元素的整体移动, 所以其时间复杂度是 O(1)
    1、Python 基本数据结构_第14张图片

3、使用列表来模拟栈

  • 假设栈要实现如下功能:
    1、Python 基本数据结构_第15张图片

  • 代码实践

# 选用 List 的尾端(index=-1)作为栈顶,此时push/pop的复杂度为O(1)
# 若选用 List 的首端(index=0)作为栈顶,其push/pop的复杂度为O(n),因为要用pop(0),insert(0,item)等来模拟出栈和入栈

class Stack(object): 
    """使用 list 来模拟栈""" 
    def __init__(self): 
        self.items = [] 
 
    def isEmpty(self): 
        return self.items == []  
 
    def push(self, item): 
        self.items.append(item) 
 
    def pop(self): 
        if not self.isEmpty(): 
	        return self.items.pop()  
		
    def peek(self): 
        if not self.isEmpty(): 
            return self.items[-1] 
 
    def size(self): 
        return len(self.items) 

# 测试用例如下图所示

1、Python 基本数据结构_第16张图片


四、队列(Queue)

1、队列的特点

  • 队列是一种线性逻辑结构, 可以用数组(list)实现, 也可以用链表实现,新数据项的添加总发生在尾端(rear),而现存数据项的移除总发生在首端(front),遵循先进先出原则:First in First out(FIFO),eg: 打印队列
    1、Python 基本数据结构_第17张图片
  • python 中提供了多种队列工具(eg: collections.deque, queue.Queue),亦可用列表来模拟
  • 其它改进:
    • 循环队列:维持队列容量的恒定(充分利用了数组的空间,还避免了数组元素整体移动的麻烦)
    • 双端队列:把栈和队列的特点结合起来, 既可以先入先出, 也可以先入后出
    • 优先队列:谁的优先级最高,谁先出队(基于二叉堆来实现的)

2、队列的基本操作

  • 包括入队和出队,下图中入队时间复杂度是 O(1),出队时间复杂度是 O(n)
    1、Python 基本数据结构_第18张图片

3、使用列表来模拟队列

  • 假设队列要实现如下功能:
    1、Python 基本数据结构_第19张图片
  • 代码实践
# 将 list 的首端作为队列的尾端,list 的末端作为队列的首端
class Queue(object):
	"""使用 list 来模拟队列"""
	def __init__(self):
		self.queue = []

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

	def enqueue(self, item):
		self.queue.insert(0, item)    # 插入队尾,时间复杂度 O(n)

	def dequeue(self):
		if not self.isEmpty():
			return self.queue.pop()   # 队首出队,时间复杂度 O(1)

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

# 测试用例如下图所示

1、Python 基本数据结构_第20张图片


五、双端队列(Deque)

1. 双端队列的特点

  • 双端队列是一种有次序的数据集,其首端和尾端都可以加入数据和移除数据
  • 某种意义上说,双端队列集成了栈和队列的能力,但双端队列并不具有内在的LIFO或者FIFO特性,如果用双端队列来模拟栈或队列,需要由使用者自行维护操作的一致性
    1、Python 基本数据结构_第21张图片

2. 使用列表来模拟双端队列

  • 假设双端队列要实现如下功能:
    1、Python 基本数据结构_第22张图片
# 将 list 的首端作为双端队列的尾端,list 的末端作为双端队列的首端
class Deque(object):
    """使用 list 来模拟双端队列"""
    def __init__(self):
        self.deque = []

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

    def addFront(self, item):       
        self.deque.append(item)       # 插入队首,时间复杂度 O(1)    

    def removeFront(self):
        if not self.isEmpty():
            return self.deque.pop()   # 队首出队,时间复杂度 O(1)

    def addRear(self, item):  
        self.deque.insert(0, item)    # 插入队尾,时间复杂度 O(n)

    def removeRear(self):
        if not self.isEmpty():
            return self.deque.pop(0)  # 队尾出队,时间复杂度 O(n)

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

# 测试用例如下图所示

1、Python 基本数据结构_第23张图片


六、哈希表(HashTable)

1、哈希表的特点

  • 哈希表(hash table)也叫作散列表,这种数据结构提供了键( Key) 和值( Value) 的映射关系
  • 只要给出一个 Key, 就可以高效查找到它所匹配的 Value, 所以哈希查找的时间复杂度接近于 O(1),而二分查找的时间复杂度为O(logn)顺序查找的时间复杂度为O(n)
    1、Python 基本数据结构_第24张图片

2、哈希函数

  • 哈希表的本质:
    • 本质上是一个数组
    • 可通过哈希函数(eg:按照数组长度进行取模运算 index = HashCode (Key) % Array.length)实现 Key 和数组下标 的转换
      1、Python 基本数据结构_第25张图片
  • 哈希冲突:
    • 由于数组的长度是有限的, 当插入的 Entry 越来越多时,不同的 Key 通过哈希函数获得的下标有可能是相同的
    • 可通过 开放寻址法和链表法 来解决哈希冲突
      • 开放寻址法原理: 当一个 Key 通过哈希函数获得对应的数组下标已被占用时,就寻找下一个空档位置
      • 链表法原理:HashMap 数组的每一个元素不仅是一个 Entry 对象, 还是一个链表的头节点;每一个 Entry 对象通过 next 指针指向它的下一个 Entry 节点;当新来的 Entry 映射到与之冲突的数组位置时, 只需要插入到对应的链表中即可
        1、Python 基本数据结构_第26张图片

六、参考资料

1、北大数据结构与算法
2、https://visualgo.net/zh
3、https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
4、https://github.com/algorithm-visualizer/algorithm-visualizer

你可能感兴趣的:(python数据结构,栈,队列,双端队列,链表,python数据结构)