为了账号安全,请及时绑定邮箱和手机立即绑定

数据结构高级入门:简洁教程

概述

本文深入探讨了数据结构高级入门的相关知识,涵盖了链表、树、图和哈希表等多种数据结构的详细讲解和应用示例。通过具体代码实例,帮助读者理解每种数据结构的工作原理和应用场景。文章还介绍了数据结构选择与优化的策略,以提高程序性能和可维护性。数据结构高级入门是每个程序员必须掌握的关键技能。

数据结构高级入门:简洁教程
数据结构基础回顾

基本概念

数据结构是计算机科学和编程中的一个重要领域,它研究数据的组织、管理和操作方式。数据结构的设计和选择对算法的效率有着至关重要的影响。常见的数据结构包括数组、链表、栈、队列、树、图等。每种数据结构都有其特定的应用场景和优缺点。

常见数据类型

  1. 整型:整数类型用于存储整数值,例如 int

    a = 42
    print(a)  # 输出 42
  2. 浮点型:浮点数类型用于存储小数,例如 float

    b = 3.14
    print(b)  # 输出 3.14
  3. 字符串:字符串类型用于存储文本数据,例如 str

    c = "Hello, world!"
    print(c)  # 输出 Hello, world!
  4. 布尔型:布尔类型用于表示真/假,例如 bool

    d = True
    print(d)  # 输出 True
链表的深入理解

单向链表

单向链表是一种线性数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。每个节点都指向链表中的下一个节点,最后一个节点指向 None

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

class LinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        last = self.head
        while last.next:
            last = last.next
        last.next = new_node

    def display(self):
        values = []
        current = self.head
        while current:
            values.append(current.data)
            current = current.next
        print(values)

linked_list = LinkedList()
linked_list.append(1)
linked_list.append(2)
linked_list.append(3)
linked_list.display()  # 输出 [1, 2, 3]

双向链表

双向链表与单向链表类似,但每个节点包含一个指向下一个节点的指针和一个指向前一个节点的指针。双向链表允许在链表中前进和后退。

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

class DoublyLinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        last = self.head
        while last.next:
            last = last.next
        last.next = new_node
        new_node.prev = last

    def display(self):
        values = []
        current = self.head
        while current:
            values.append(current.data)
            current = current.next
        print(values)

doubly_linked_list = DoublyLinkedList()
doubly_linked_list.append(1)
doubly_linked_list.append(2)
doubly_linked_list.append(3)
doubly_linked_list.display()  # 输出 [1, 2, 3]

循环链表

循环链表是一种特殊的链表,最后一个节点的指针指向链表的第一个节点,形成一个环。循环链表特别适用于需要循环遍历的数据结构。

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

class CircularLinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            new_node.next = self.head
            return
        last = self.head
        while last.next != self.head:
            last = last.next
        last.next = new_node
        new_node.next = self.head

    def display(self):
        values = []
        current = self.head
        if self.head:
            values.append(current.data)
            current = current.next
            while current != self.head:
                values.append(current.data)
                current = current.next
        print(values)

circular_linked_list = CircularLinkedList()
circular_linked_list.append(1)
circular_linked_list.append(2)
circular_linked_list.append(3)
circular_linked_list.display()  # 输出 [1, 2, 3]
树结构的进阶学习

二叉树

二叉树是一种特殊的树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树是许多数据结构和算法的基础。

class TreeNode:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None

class BinarySearchTree:
    def __init__(self):
        self.root = None

    def insert(self, data):
        if not self.root:
            self.root = TreeNode(data)
            return
        self._insert(self.root, data)

    def _insert(self, node, data):
        if data < node.data:
            if not node.left:
                node.left = TreeNode(data)
            else:
                self._insert(node.left, data)
        else:
            if not node.right:
                node.right = TreeNode(data)
            else:
                self._insert(node.right, data)

    def inorder_traversal(self):
        return self._inorder_traversal(self.root)

    def _inorder_traversal(self, node):
        if node:
            return self._inorder_traversal(node.left) + [node.data] + self._inorder_traversal(node.right)
        return []

bst = BinarySearchTree()
bst.insert(5)
bst.insert(3)
bst.insert(8)
bst.insert(1)
bst.insert(4)
print(bst.inorder_traversal())  # 输出 [1, 3, 4, 5, 8]

平衡树

平衡树是一种特殊的二叉树,其左右子树的高度差不超过1。平衡树的典型代表是AVL树和红黑树。

AVL树

AVL树是一种自平衡二叉搜索树,其中任何节点的两个子树的高度差最多为1。AVL树通过旋转操作来保持平衡。

class AVLNode:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
        self.height = 1

class AVLTree:
    def insert(self, root, key):
        if not root:
            return AVLNode(key)
        elif key < root.data:
            root.left = self.insert(root.left, key)
        else:
            root.right = self.insert(root.right, key)

        root.height = 1 + max(self.get_height(root.left), self.get_height(root.right))

        balance = self.get_balance(root)

        if balance > 1 and key < root.left.data:
            return self.right_rotate(root)

        if balance < -1 and key > root.right.data:
            return self.left_rotate(root)

        if balance > 1 and key > root.left.data:
            root.left = self.left_rotate(root.left)
            return self.right_rotate(root)

        if balance < -1 and key < root.right.data:
            root.right = self.right_rotate(root.right)
            return self.left_rotate(root)

        return root

    def left_rotate(self, z):
        y = z.right
        T2 = y.left
        y.left = z
        z.right = T2
        z.height = 1 + max(self.get_height(z.left), self.get_height(z.right))
        y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))
        return y

    def right_rotate(self, z):
        y = z.left
        T3 = y.right
        y.right = z
        z.left = T3
        z.height = 1 + max(self.get_height(z.left), self.get_height(z.right))
        y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))
        return y

    def get_height(self, root):
        if not root:
            return 0
        return root.height

    def get_balance(self, root):
        if not root:
            return 0
        return self.get_height(root.left) - self.get_height(root.right)

avl_tree = AVLTree()
root = None
root = avl_tree.insert(root, 10)
root = avl_tree.insert(root, 20)
root = avl_tree.insert(root, 30)
root = avl_tree.insert(root, 40)
root = avl_tree.insert(root, 50)
root = avl_tree.insert(root, 25)

堆是一种特殊的完全二叉树,其中每个节点的值都大于或等于(最大堆)或小于或等于(最小堆)其子节点的值。堆常用于实现优先队列。

最大堆

最大堆是一种特殊的完全二叉树,每个节点的值都大于或等于其子节点的值。

def heapify(arr, n, i):
    largest = i
    left = 2 * i + 1
    right = 2 * i + 2

    if left < n and arr[i] < arr[left]:
        largest = left

    if right < n and arr[largest] < arr[right]:
        largest = right

    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def build_max_heap(arr):
    n = len(arr)
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

def heap_sort(arr):
    n = len(arr)
    build_max_heap(arr)
    for i in range(n - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

arr = [12, 11, 13, 5, 6, 7]
heap_sort(arr)
print(arr)  # 输出 [5, 6, 7, 11, 12, 13]
图结构的入门

图的基本概念

图是一种非线性的数据结构,由节点(顶点)和边(连接顶点的线)组成。图可以是无向图(边没有方向)或有向图(边有方向)。

图的表示方法

图的表示方法主要有两种:邻接矩阵和邻接表。

邻接矩阵

邻接矩阵是一种使用二维数组表示图的方法。矩阵的行和列分别表示顶点,矩阵元素表示顶点之间的连接。

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = [[0 for column in range(vertices)] for row in range(vertices)]

    def add_edge(self, u, v):
        self.graph[u][v] = 1
        self.graph[v][u] = 1

    def print_matrix(self):
        for row in self.graph:
            print(row)

g = Graph(4)
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 2)
g.add_edge(2, 3)
g.print_matrix()

邻接表

邻接表是一种使用链表表示图的方法。每个顶点都关联一个链表,链表包含与该顶点相连的其他顶点。

class AdjNode:
    def __init__(self, v):
        self.vertex = v
        self.next = None

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = [None] * vertices

    def add_edge(self, src, dest):
        node = AdjNode(dest)
        node.next = self.graph[src]
        self.graph[src] = node

        # For undirected graph, add an edge from dest to src as well
        node = AdjNode(src)
        node.next = self.graph[dest]
        self.graph[dest] = node

    def print_graph(self):
        for i in range(self.V):
            print(f"Adjacency list of vertex {i}")
            temp = self.graph[i]
            while temp:
                print(f" -> {temp.vertex}", end="")
                temp = temp.next
            print()

g = Graph(4)
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 2)
g.add_edge(2, 3)
g.print_graph()

常见的图算法

深度优先搜索(DFS)

深度优先搜索是一种遍历图的方法,从一个顶点开始,尽可能深地访问相邻的顶点。

def dfs_util(graph, v, visited):
    visited[v] = True
    print(v, end=' ')

    for i in graph[v]:
        if not visited[i]:
            dfs_util(graph, i, visited)

def dfs(graph, v):
    visited = [False] * len(graph)
    dfs_util(graph, v, visited)

graph = [
    [1, 2],
    [0, 2],
    [0, 1, 3],
    [2]
]
dfs(graph, 0)

广度优先搜索(BFS)

广度优先搜索是一种遍历图的方法,从一个顶点开始,按层次访问相邻的顶点。

from collections import deque

def bfs_util(graph, v, visited):
    visited[v] = True
    queue = deque([v])

    while queue:
        v = queue.popleft()
        print(v, end=' ')

        for i in graph[v]:
            if not visited[i]:
                visited[i] = True
                queue.append(i)

def bfs(graph, v):
    visited = [False] * len(graph)
    bfs_util(graph, v, visited)

graph = [
    [1, 2],
    [0, 2],
    [0, 1, 3],
    [2]
]
bfs(graph, 0)

最短路径算法(Dijkstra算法)

Dijkstra算法用于计算从源节点到其他所有节点的最短路径。

import sys

def dijkstra(graph, src):
    n = len(graph)
    dist = [sys.maxsize] * n
    dist[src] = 0
    visited = [False] * n
    pq = [(0, src)]

    while pq:
        dist_u, u = min(pq)
        pq.remove((dist_u, u))
        visited[u] = True

        for v in range(n):
            if graph[u][v] and not visited[v]:
                new_dist = dist_u + graph[u][v]
                if new_dist < dist[v]:
                    dist[v] = new_dist
                    pq.append((new_dist, v))

    return dist

graph = [
    [0, 4, 0, 0, 0, 0, 0, 8, 0],
    [4, 0, 8, 0, 0, 0, 0, 11, 0],
    [0, 8, 0, 7, 0, 0, 2, 0, 0],
    [0, 0, 7, 0, 9, 14, 0, 0, 0],
    [0, 0, 0, 9, 0, 10, 0, 0, 0],
    [0, 0, 0, 14, 10, 0, 2, 0, 0],
    [0, 0, 2, 0, 0, 2, 0, 1, 6],
    [8, 11, 0, 0, 0, 0, 1, 0, 7],
    [0, 0, 0, 0, 0, 0, 6, 7, 0]
]

print(dijkstra(graph, 0))  # 输出 [0, 4, 12, 19, 21, 11, 9, 8, 14]
哈希表的详解

基本原理

哈希表是一种数据结构,用于存储键值对。哈希表通过哈希函数将键映射到一个地址,从而实现快速的插入、删除和查找操作。

冲突解决方法

哈希冲突是指不同的键通过哈希函数映射到同一个地址。常见的冲突解决方法包括链地址法和开放地址法。

链地址法

链地址法通过在每个地址上使用一个链表来解决冲突。当发生冲突时,新的节点被添加到链表中。

class ListNode:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.next = None

class HashTable:
    def __init__(self, capacity):
        self.capacity = capacity
        self.table = [None] * capacity

    def _hash(self, key):
        return hash(key) % self.capacity

    def put(self, key, value):
        index = self._hash(key)
        if not self.table[index]:
            self.table[index] = ListNode(key, value)
        else:
            current = self.table[index]
            while current.next:
                if current.key == key:
                    current.value = value
                    return
                current = current.next
            current.next = ListNode(key, value)

    def get(self, key):
        index = self._hash(key)
        current = self.table[index]
        while current:
            if current.key == key:
                return current.value
            current = current.next
        return None

hash_table = HashTable(10)
hash_table.put("apple", 5)
hash_table.put("banana", 10)
hash_table.put("cherry", 15)
print(hash_table.get("apple"))  # 输出 5
print(hash_table.get("banana"))  # 输出 10
print(hash_table.get("cherry"))  # 输出 15

开放地址法

开放地址法通过探查其他地址来解决冲突。当发生冲突时,使用一个探查函数来找到下一个可用地址。

class HashTable:
    def __init__(self, capacity):
        self.capacity = capacity
        self.table = [None] * capacity

    def _hash(self, key):
        return hash(key) % self.capacity

    def _probe(self, key, i):
        return (self._hash(key) + i) % self.capacity

    def put(self, key, value):
        for i in range(self.capacity):
            index = self._probe(key, i)
            if not self.table[index]:
                self.table[index] = (key, value)
                return
            if self.table[index][0] == key:
                self.table[index] = (key, value)
                return

    def get(self, key):
        for i in range(self.capacity):
            index = self._probe(key, i)
            if not self.table[index]:
                return None
            if self.table[index][0] == key:
                return self.table[index][1]
        return None

hash_table = HashTable(10)
hash_table.put("apple", 5)
hash_table.put("banana", 10)
hash_table.put("cherry", 15)
print(hash_table.get("apple"))  # 输出 5
print(hash_table.get("banana"))  # 输出 10
print(hash_table.get("cherry"))  # 输出 15

实际应用案例

哈希表在实际应用中被广泛使用,例如数据库中的索引、缓存系统中的数据存储和查找、编译器中的符号表等。

class Cache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache = {}

    def put(self, key, value):
        if len(self.cache) >= self.capacity:
            self.cache.pop(next(iter(self.cache)))
        self.cache[key] = value

    def get(self, key):
        return self.cache.get(key, None)

cache = Cache(3)
cache.put("apple", 5)
cache.put("banana", 10)
cache.put("cherry", 15)
cache.put("date", 20)
print(cache.get("apple"))  # 输出 None
print(cache.get("banana"))  # 输出 10
print(cache.get("cherry"))  # 输出 15
print(cache.get("date"))  # 输出 20
数据结构在实际问题中的应用

典型问题案例分析

  1. LRU缓存

LRU(Least Recently Used)缓存是一种常用的数据结构,用于缓存最近使用的数据。当缓存满时,最近最少使用的数据将被移除。

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity):
        self.cache = OrderedDict()
        self.capacity = capacity

    def get(self, key):
        if key not in self.cache:
            return -1
        self.cache.move_to_end(key)
        return self.cache[key]

    def put(self, key, value):
        if key in self.cache:
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            self.cache.popitem(last=False)

cache = LRUCache(3)
cache.put("apple", 5)
cache.put("banana", 10)
cache.put("cherry", 15)
print(cache.get("apple"))  # 输出 5
print(cache.get("banana"))  # 输出 10
cache.put("date", 20)
print(cache.get("cherry"))  # 输出 15
print(cache.get("date"))  # 输出 20
print(cache.get("apple"))  # 输出 -1
  1. 拓扑排序

拓扑排序是一种算法,用于将图中的节点按顺序排列,使得有指向关系的节点前在序列中的节点排在后。

from collections import defaultdict, deque

def topological_sort(graph):
    in_degree = defaultdict(int)
    for node in graph:
        for neighbor in graph[node]:
            in_degree[neighbor] += 1
    queue = deque([node for node in graph if in_degree[node] == 0])
    result = []

    while queue:
        node = queue.popleft()
        result.append(node)
        for neighbor in graph[node]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                queue.append(neighbor)

    return result

graph = {
    'A': ['B', 'C'],
    'B': ['D'],
    'C': ['D'],
    'D': []
}

print(topological_sort(graph))  # 输出 ['A', 'B', 'C', 'D']

数据结构选择与优化策略

在选择和优化数据结构时,需要考虑以下几个因素:

  1. 时间复杂度:数据结构的操作时间复杂度决定了算法的效率,例如数组的查找操作是 O(1),而链表的查找操作是 O(n)。
  2. 空间复杂度:数据结构的空间复杂度决定了算法的空间消耗,例如哈希表的空间复杂度通常为 O(n)。
  3. 应用场景:不同的数据结构适用于不同的应用场景,例如栈适用于递归调用场景,队列适用于任务调度场景,树适用于层级结构场景。
  4. 并发访问:在多线程环境中,需要考虑数据结构的并发访问安全性,例如使用锁机制保护共享资源。

有效的数据结构选择和优化策略包括:

# 示例代码展示如何选择和优化数据结构
def example_strategy():
    # 示例:优化缓存结构
    from collections import OrderedDict

    class OptimizedCache:
        def __init__(self, capacity):
            self.capacity = capacity
            self.cache = OrderedDict()

        def get(self, key):
            if key not in self.cache:
                return None
            self.cache.move_to_end(key)
            return self.cache[key]

        def put(self, key, value):
            if key in self.cache:
                self.cache.move_to_end(key)
            self.cache[key] = value
            if len(self.cache) > self.capacity:
                self.cache.popitem(last=False)

    cache = OptimizedCache(3)
    cache.put("apple", 5)
    cache.put("banana", 10)
    cache.put("cherry", 15)
    print(cache.get("apple"))  # 输出 5
    print(cache.get("banana"))  # 输出 10
    cache.put("date", 20)
    print(cache.get("cherry"))  # 输出 15
    print(cache.get("date"))  # 输出 20
    print(cache.get("apple"))  # 输出 None

    # 示例:使用动态规划优化递归算法
    def fibonacci(n, memo={}):
        if n in memo:
            return memo[n]
        if n <= 1:
            return n
        memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
        return memo[n]

    print(fibonacci(10))  # 输出 55

通过合理选择和优化数据结构,可以显著提高程序的性能和可维护性。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消