Skip to content

基础数据结构与排序

本章节整理自 jwasham/coding-interview-university,重点关注面试中的实现要求

更多内容请参考:数据结构 - 理论讲解与算法分析


数组 (Array)

实现要求

方法说明时间复杂度
size()返回元素数量O(1)
capacity()返回容量大小O(1)
is_empty()是否为空O(1)
at(index)返回指定索引元素,超界报错O(1)
push(item)末尾添加元素O(1) 均摊
insert(index, item)指定位置插入O(n)
prepend(item)头部插入(用 insert)O(n)
pop()末尾删除并返回O(1) 均摊
delete(index)指定位置删除O(n)
remove(item)删除所有匹配项O(n)
find(item)查找元素,返回首次索引O(n)
resize(new_capacity)扩容/缩容O(n)

关键实现细节

python
class Array:
    def __init__(self, initial_capacity=16):
        self.capacity = initial_capacity if initial_capacity >= 16 else 16
        self.size = 0
        self.data = [None] * self.capacity

    def _resize(self, new_capacity):
        """动态扩容"""
        new_data = [None] * new_capacity
        for i in range(self.size):
            new_data[i] = self.data[i]
        self.data = new_data
        self.capacity = new_capacity

    def push(self, item):
        """末尾添加,均摊 O(1)"""
        if self.size == self.capacity:
            self._resize(self.capacity * 2)  # 容量翻倍
        self.data[self.size] = item
        self.size += 1

    def pop(self):
        """末尾删除,均摊 O(1)"""
        if self.size == 0:
            return None
        item = self.data[self.size - 1]
        self.size -= 1
        # 缩容:当 size 为容量的 1/4 时,缩到一半
        if self.size > 0 and self.size == self.capacity // 4:
            self._resize(self.capacity // 2)
        return item

复杂度

操作时间复杂度
尾部添加/删除O(1) 均摊
按索引访问O(1)
任意位置插入/删除O(n)
空间O(n)

链表 (Linked List)

单链表实现要求

方法说明时间复杂度
size()返回元素数量O(1) 或 O(n)
empty()是否为空O(1)
value_at(index)返回第 n 个元素O(n)
push_front(value)头部插入O(1)
pop_front()头部删除并返回值O(1)
push_back(value)尾部插入O(1) 或 O(n)
pop_back()尾部删除并返回值O(n) 或 O(1)
front()获取头部元素O(1)
back()获取尾部元素O(1) 或 O(n)
insert(index, value)指定位置插入O(n)
erase(index)删除指定位置O(n)
value_n_from_end(n)返回倒数第 n 个O(n)
reverse()反转链表O(n)
remove_value(value)删除第一个匹配项O(n)

Python 实现

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

class LinkedList:
    def __init__(self):
        self.head = None
        self.tail = None  # 尾指针优化
        self.size = 0

    def push_front(self, value):
        """O(1)"""
        node = Node(value)
        node.next = self.head
        self.head = node
        if self.tail is None:
            self.tail = node
        self.size += 1

    def pop_front(self):
        """O(1)"""
        if self.head is None:
            return None
        value = self.head.value
        self.head = self.head.next
        if self.head is None:
            self.tail = None
        self.size -= 1
        return value

    def push_back(self, value):
        """O(1) with tail pointer"""
        node = Node(value)
        if self.tail:
            self.tail.next = node
            self.tail = node
        else:
            self.head = self.tail = node
        self.size += 1

    def reverse(self):
        """反转链表 O(n)"""
        prev = None
        curr = self.head
        self.tail = self.head
        while curr:
            next_node = curr.next
            curr.next = prev
            prev = curr
            curr = next_node
        self.head = prev

链表 vs 数组

特性链表数组
随机访问O(n)O(1)
头部插入/删除O(1)O(n)
尾部插入O(1)O(1) 均摊
中间插入O(n)O(n)
空间开销O(n) + 指针O(n) 连续内存

栈 (Stack)

实现要求

方法说明
push(item)入栈
pop()出栈并返回
peek()查看栈顶
is_empty()是否为空

实现:使用数组

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

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

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

    def peek(self):
        return self.items[-1] if self.items else None

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

复杂度

操作时间复杂度
pushO(1)
popO(1)
peekO(1)

队列 (Queue)

实现要求

方法说明
enqueue(value)入队
dequeue()出队并返回
empty()是否为空

实现:链表 + 尾指针

python
class Queue:
    def __init__(self):
        self.head = None
        self.tail = None

    def enqueue(self, value):
        node = Node(value)
        if self.tail:
            self.tail.next = node
            self.tail = node
        else:
            self.head = self.tail = node

    def dequeue(self):
        if self.head is None:
            return None
        value = self.head.value
        self.head = self.head.next
        if self.head is None:
            self.tail = None
        return value

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

实现:循环缓冲区(固定大小数组)

python
class CircularQueue:
    def __init__(self, capacity):
        self.capacity = capacity
        self.queue = [None] * capacity
        self.head = 0
        self.tail = 0
        self.size = 0

    def enqueue(self, value):
        if self.size == self.capacity:
            return False
        self.queue[self.tail] = value
        self.tail = (self.tail + 1) % self.capacity
        self.size += 1
        return True

    def dequeue(self):
        if self.size == 0:
            return None
        value = self.queue[self.head]
        self.head = (self.head + 1) % self.capacity
        self.size -= 1
        return value

    def empty(self):
        return self.size == 0

    def full(self):
        return self.size == self.capacity

哈希表 (Hash Table)

实现要求

方法说明
hash(key, m)哈希函数
add(key, value)添加/更新
exists(key)键是否存在
get(key)获取值
remove(key)删除

实现:线性探测 + 数组

python
class HashTable:
    def __init__(self, size=16):
        self.size = size
        self.keys = [None] * size
        self.values = [None] * size

    def _hash(self, key):
        """简单哈希函数"""
        return hash(key) % self.size

    def add(self, key, value):
        """线性探测解决冲突"""
        index = self._hash(key)
        start_index = index
        while self.keys[index] is not None:
            if self.keys[index] == key:
                self.values[index] = value
                return
            index = (index + 1) % self.size
            if index == start_index:
                raise Exception("Hash table is full")
        self.keys[index] = key
        self.values[index] = value

    def get(self, key):
        index = self._hash(key)
        start_index = index
        while self.keys[index] is not None:
            if self.keys[index] == key:
                return self.values[index]
            index = (index + 1) % self.size
            if index == start_index:
                break
        return None

    def remove(self, key):
        index = self._hash(key)
        start_index = index
        while self.keys[index] is not None:
            if self.keys[index] == key:
                self.keys[index] = None
                self.values[index] = None
                return True
            index = (index + 1) % self.size
            if index == start_index:
                break
        return False

    def exists(self, key):
        return self.get(key) is not None

复杂度

操作平均最坏
查找O(1)O(n)
插入O(1)O(n)
删除O(1)O(n)

排序算法

面试必会排序

算法平均最坏空间稳定
归并排序O(n log n)O(n log n)O(n)
快速排序O(n log n)O(n²)O(log n)
堆排序O(n log n)O(n log n)O(1)
插入排序O(n²)O(n²)O(1)
选择排序O(n²)O(n²)O(1)

NOTE

冒泡排序除非 n<=16,否则不要使用。

归并排序实现

python
def merge_sort(arr):
    """O(n log n), 稳定"""
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])

    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

快速排序实现

python
def quick_sort(arr):
    """O(n log n) 平均, 不稳定"""
    _quick_sort(arr, 0, len(arr) - 1)
    return arr

def _quick_sort(arr, low, high):
    if low < high:
        pivot_index = partition(arr, low, high)
        _quick_sort(arr, low, pivot_index - 1)
        _quick_sort(arr, pivot_index + 1, high)

def partition(arr, low, high):
    """三数取中优化"""
    mid = (low + high) // 2
    # 将中位数放到高位
    if arr[mid] > arr[high]:
        arr[mid], arr[high] = arr[high], arr[mid]
    if arr[low] > arr[high]:
        arr[low], arr[high] = arr[high], arr[low]
    if arr[mid] > arr[low]:
        arr[mid], arr[low] = arr[low], arr[mid]

    pivot = arr[low]
    i = low + 1
    j = high
    while True:
        while i <= j and arr[i] <= pivot:
            i += 1
        while i <= j and arr[j] >= pivot:
            j -= 1
        if i > j:
            break
        arr[i], arr[j] = arr[j], arr[i]
    arr[low], arr[j] = arr[j], arr[low]
    return j

堆排序实现

python
def heap_sort(arr):
    """O(n log n), 不稳定"""
    n = len(arr)

    # 构建最大堆
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # 逐个提取元素
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]
        heapify(arr, i, 0)

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

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

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

稳定性

算法稳定性
归并排序✓ 稳定
插入排序✓ 稳定
冒泡排序✓ 稳定
快速排序✗ 不稳定
堆排序✗ 不稳定
选择排序✗ 不稳定

相关资源

基于 VitePress 构建