手记

数据结构高级入门教程

数据结构是计算机科学中的基础,它涉及到如何组织和存储数据,以便于高效地操作和访问。本文将从基础知识回顾开始,逐步深入到高级数据结构的介绍,最后以实际应用和优化技巧收尾。

数据结构基础回顾

简单回顾数组与链表

数组是一种基本的数据结构,它将一组相同类型的元素按照索引顺序存储。数组的优点是可以通过索引快速访问任意一个位置的元素,但是缺点是插入和删除操作会比较慢,因为需要移动后续的元素。

链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表的优点是插入和删除操作只需要修改指针,但是访问某个特定位置的元素需要遍历整个链表。

数组示例代码

# Python代码示例
arr = [1, 2, 3, 4, 5]
print(arr[2])  # 输出 3

链表示例代码

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):
        current = self.head
        while current:
            print(current.data, end=" -> ")
            current = current.next
        print("None")

# 使用示例
ll = LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.display()  # 输出 1 -> 2 -> 3 -> None

重温栈与队列的基本概念

栈是一种只能在一端进行插入和删除操作的线性数据结构,遵循后进先出(LIFO)原则。而队列是一种只能在一端插入而在另一端删除的线性数据结构,遵循先进先出(FIFO)原则。

栈示例代码

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.is_empty():
            return self.items.pop()

    def is_empty(self):
        return len(self.items) == 0

    def peek(self):
        if not self.is_empty():
            return self.items[-1]

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

# 使用示例
s = Stack()
s.push(1)
s.push(2)
print(s.pop())  # 输出 2
print(s.peek())  # 输出 1

队列示例代码

class Queue:
    def __init__(self):
        self.items = []

    def enqueue(self, item):
        self.items.append(item)

    def dequeue(self):
        if not self.is_empty():
            return self.items.pop(0)

    def is_empty(self):
        return len(self.items) == 0

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

# 使用示例
q = Queue()
q.enqueue(1)
q.enqueue(2)
print(q.dequeue())  # 输出 1
print(q.size())  # 输出 1
树与图的初步探索

二叉树的定义与基本操作

二叉树是一种特殊的树形结构,每个节点最多有两个子节点,分别是左子节点和右子节点。二叉树广泛用于各种算法和数据结构,例如二叉查找树、堆等。

二叉树的基本操作包括插入、删除、查找等。

二叉树插入示例代码

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

def insert(root, key):
    if root is None:
        return TreeNode(key)
    else:
        if root.val < key:
            root.right = insert(root.right, key)
        else:
            root.left = insert(root.left, key)
    return root

# 使用示例
root = None
root = insert(root, 8)
root = insert(root, 3)
root = insert(root, 10)
root = insert(root, 1)
root = insert(root, 6)
root = insert(root, 14)
root = insert(root, 4)
root = insert(root, 7)

图的基本概念与表示方法

图是一种非线性的数据结构,由顶点(节点)和边组成。顶点可以表示实体,边可以表示实体之间的关系。图可以有向也可以无向,边可以有权重。

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

邻接矩阵示例代码

def create_graph_matrix(n):
    return [[0] * n for _ in range(n)]

def add_edge_matrix(graph, v1, v2):
    graph[v1][v2] = 1
    graph[v2][v1] = 1

# 使用示例
graph_matrix = create_graph_matrix(4)
add_edge_matrix(graph_matrix, 0, 1)
add_edge_matrix(graph_matrix, 0, 2)
add_edge_matrix(graph_matrix, 1, 2)
add_edge_matrix(graph_matrix, 2, 3)
print(graph_matrix)

邻接表示例代码

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

class Graph:
    def __init__(self, num_vertices):
        self.num_vertices = num_vertices
        self.adj_list = {i: [] for i in range(num_vertices)}

    def add_edge(self, v1, v2):
        self.adj_list[v1].append(Node(v2))
        self.adj_list[v2].append(Node(v1))

# 使用示例
g = Graph(4)
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 2)
g.add_edge(2, 3)
print(g.adj_list)
哈希表的深入理解

哈希函数与冲突处理

哈希表是一种通过哈希函数将键映射到数组索引的数据结构。哈希函数将任意长度的输入值映射为固定长度的输出值,理想的哈希函数应该均匀分布,减少冲突。

冲突处理主要有两种方法:开放地址法和链地址法。

链地址法示例代码

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

class HashTable:
    def __init__(self, capacity=1000):
        self.capacity = capacity
        self.size = 0
        self.buckets = [None] * capacity

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

    def put(self, key, value):
        index = self._hash(key)
        if self.buckets[index] is None:
            self.buckets[index] = ListNode(key, value)
            self.size += 1
        else:
            current = self.buckets[index]
            while current.next:
                current = current.next
            current.next = ListNode(key, value)
            self.size += 1

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

# 使用示例
ht = HashTable()
ht.put("apple", 100)
ht.put("banana", 200)
print(ht.get("apple"))  # 输出 100
print(ht.get("banana"))  # 输出 200

哈希表的应用场景

哈希表广泛应用于各种场景,例如数据库索引、缓存系统、软件的高速查找等。

  • 数据库索引:哈希表可以用来实现数据库中的索引,提高查询速度。
  • 缓存系统:哈希表可以用来实现缓存系统,快速响应用户的请求。
  • 软件的高速查找:哈希表可以用来实现软件中的高速查找功能,例如字典、符号表等。

数据库索引示例代码

class HashIndex:
    def __init__(self, size=1000):
        self.size = size
        self.buckets = [None] * size

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

    def insert(self, key, value):
        index = self._hash(key)
        if not self.buckets[index]:
            self.buckets[index] = []
        self.buckets[index].append((key, value))

    def get(self, key):
        index = self._hash(key)
        if self.buckets[index]:
            for k, v in self.buckets[index]:
                if k == key:
                    return v
        return None

# 使用示例
index = HashIndex()
index.insert("apple", 100)
index.insert("banana", 200)
print(index.get("apple"))  # 输出 100
print(index.get("banana"))  # 输出 200
高级数据结构介绍

平衡二叉树(如AVL树、红黑树)

平衡二叉树是一种自平衡的二叉搜索树,能够保持树的平衡,从而保证操作的时间复杂度为O(log n)。AVL树和红黑树是比较常见的两种平衡二叉树。

  • AVL树:每个节点的左子树和右子树的高度差不超过1。
  • 红黑树:每个节点是红色或黑色,根节点是黑色,所有叶子节点是黑色的虚节点,每个红色节点的两个子节点都是黑色的。

AVL树示例代码

class TreeNode:
    def __init__(self, key, left=None, right=None, height=1):
        self.key = key
        self.left = left
        self.right = right
        self.height = height

class AVLTree:
    def insert(self, root, key):
        if not root:
            return TreeNode(key)
        elif key < root.key:
            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.key:
            return self.right_rotate(root)
        if balance < -1 and key > root.right.key:
            return self.left_rotate(root)
        if balance > 1 and key > root.left.key:
            root.left = self.left_rotate(root.left)
            return self.right_rotate(root)
        if balance < -1 and key < root.right.key:
            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)

红黑树示例代码

class RBNode:
    def __init__(self, key, color='red'):
        self.key = key
        self.left = None
        self.right = None
        self.color = color

class RBTree:
    def __init__(self, root=None):
        self.root = root

    def insert(self, key):
        new_node = RBNode(key)
        if not self.root:
            self.root = new_node
            return
        self.root = self._insert(self.root, new_node)
        self.root.color = 'black'

    def _insert(self, root, node):
        if not root:
            return node
        if node.key < root.key:
            root.left = self._insert(root.left, node)
        else:
            root.right = self._insert(root.right, node)
        return self._balance(root)

    def _balance(self, root):
        if root.right and root.right.color == 'red' and (not root.left or root.left.color == 'black'):
            root = self._right_rotate(root)
        if root.left and root.left.color == 'red' and root.left.left and root.left.left.color == 'red':
            root = self._left_rotate(root)
        if root.left and root.left.color == 'red' and root.right and root.right.color == 'red':
            self._flip_colors(root)
        return root

    def _right_rotate(self, root):
        new_root = root.left
        root.left = new_root.right
        new_root.right = root
        new_root.color = root.color
        root.color = 'red'
        return new_root

    def _left_rotate(self, root):
        new_root = root.right
        root.right = new_root.left
        new_root.left = root
        new_root.color = root.color
        root.color = 'red'
        return new_root

    def _flip_colors(self, root):
        root.color = 'red'
        root.left.color = 'black'
        root.right.color = 'black'

# 使用示例
rb_tree = RBTree()
rb_tree.insert(10)
rb_tree.insert(20)
rb_tree.insert(30)
rb_tree.insert(40)
rb_tree.insert(50)
rb_tree.insert(25)

堆与优先队列

堆是一种特殊的树形结构,通常用于实现优先队列。堆分为最大堆和最小堆,最大堆的根节点是最大的,而最小堆的根节点是最小的。

  • 最大堆:根节点大于等于左右子节点。
  • 最小堆:根节点小于等于左右子节点。

最大堆示例代码

import heapq

class MaxHeap:
    def __init__(self):
        self.heap = []

    def insert(self, key):
        heapq.heappush(self.heap, -key)

    def extract_max(self):
        if self.heap:
            return -heapq.heappop(self.heap)
        return None

    def get_max(self):
        if self.heap:
            return -self.heap[0]
        return None

# 使用示例
max_heap = MaxHeap()
max_heap.insert(10)
max_heap.insert(20)
max_heap.insert(30)
print(max_heap.get_max())  # 输出 30
print(max_heap.extract_max())  # 输出 30
print(max_heap.get_max())  # 输出 20

优先队列示例代码

class PriorityQueue:
    def __init__(self):
        self.heap = []

    def insert(self, priority, item):
        heapq.heappush(self.heap, (priority, item))

    def remove(self):
        if self.heap:
            return heapq.heappop(self.heap)
        return None

    def get(self):
        if self.heap:
            return self.heap[0]
        return None

# 使用示例
pq = PriorityQueue()
pq.insert(1, "task1")
pq.insert(3, "task3")
pq.insert(2, "task2")
print(pq.get())  # 输出 (1, 'task1')
print(pq.remove())  # 输出 (1, 'task1')
print(pq.get())  # 输出 (2, 'task2')
数据结构应用实例

实战案例:使用哈希表实现字典

字典是一种常用的数据结构,用于存储键值对。哈希表可以高效地实现字典的功能,因为哈希表的插入和查找操作时间复杂度都是O(1)。

实现字典示例代码

class Dictionary:
    def __init__(self):
        self.capacity = 1000
        self.size = 0
        self.buckets = [None] * self.capacity

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

    def put(self, key, value):
        index = self._hash(key)
        if self.buckets[index] is None:
            self.buckets[index] = ListNode(key, value)
            self.size += 1
        else:
            current = self.buckets[index]
            while current:
                if current.key == key:
                    current.value = value
                    return
                current = current.next
            new_node = ListNode(key, value)
            new_node.next = self.buckets[index]
            self.buckets[index] = new_node
            self.size += 1

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

# 使用示例
dict = Dictionary()
dict.put("apple", 100)
dict.put("banana", 200)
print(dict.get("apple"))  # 输出 100
print(dict.get("banana"))  # 输出 200

实战案例:使用树与图解决实际问题

树和图在实际应用中非常广泛,可以用来解决各种实际问题,例如路径规划、社交网络分析等。

社交网络分析示例代码

from collections import defaultdict

class Graph:
    def __init__(self):
        self.graph = defaultdict(list)

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

    def bfs(self, start):
        visited = [False] * (max(self.graph) + 1)
        queue = [start]
        visited[start] = True
        while queue:
            start = queue.pop(0)
            print(start, end=" ")
            for i in self.graph[start]:
                if not visited[i]:
                    queue.append(i)
                    visited[i] = True

    def dfs(self, start):
        visited = [False] * (max(self.graph) + 1)
        stack = [start]
        while stack:
            start = stack.pop()
            if not visited[start]:
                print(start, end=" ")
                visited[start] = True
                for node in self.graph[start]:
                    stack.append(node)

# 使用示例
g = Graph()
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 2)
g.add_edge(2, 0)
g.add_edge(2, 3)
g.add_edge(3, 3)
print("BFS:")
g.bfs(2)  # 输出 2 0 1 3
print("\nDFS:")
g.dfs(2)  # 输出 2 0 1 3
数据结构优化技巧

时间复杂度与空间复杂度分析

时间复杂度是指算法执行所需的时间,通常用大O符号表示。空间复杂度是指算法执行所需的额外空间,也用大O符号表示。

  • 时间复杂度:表示算法执行时间的增长趋势,常用O(1)、O(n)、O(n^2)等表示。
  • 空间复杂度:表示算法执行所需的额外空间大小,常用O(1)、O(n)、O(n^2)等表示。

分析示例代码

def linear_search(arr, target):
    for i in range(len(arr)):
        if arr[i] == target:
            return i
    return -1

# 时间复杂度 O(n)
# 空间复杂度 O(1)

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1

# 时间复杂度 O(log n)
# 空间复杂度 O(1)

常见的优化策略与方法

优化数据结构的关键在于减少不必要的操作,提高算法的效率。以下是一些常见的优化策略:

  • 减少不必要的操作:通过优化算法减少不必要的计算和访问。
  • 使用高效的数据结构:选择合适的数据结构可以提高算法的效率。
  • 空间换时间:使用额外的空间来减少时间复杂度。
  • 缓存机制:使用缓存机制减少重复计算。
  • 并行处理:利用多核处理器进行并行处理。

缓存机制示例代码

class MemoizedFibonacci:
    def __init__(self):
        self.cache = {}

    def fib(self, n):
        if n in self.cache:
            return self.cache[n]
        if n == 0:
            return 0
        if n == 1:
            return 1
        result = self.fib(n - 1) + self.fib(n - 2)
        self.cache[n] = result
        return result

# 使用示例
memoized_fib = MemoizedFibonacci()
print(memoized_fib.fib(10))  # 输出 55

通过以上内容的学习,读者应该能够掌握数据结构的基础知识和高级概念,并在实际应用中灵活使用各种数据结构。希望本文能帮助你更好地理解和应用数据结构,提高你的编程技能。

0人推荐
随时随地看视频
慕课网APP