图结构与高级数据结构笔记二

  • 学习内容:

    • 哈希表(Hash Table):
      • 哈希函数、冲突解决方法(拉链法、开放地址法)。
      • 哈希表的应用场景及优化策略。
    • Trie树(前缀树):
      • Trie树的基本概念及实现。
      • Trie树在字符串处理中的应用。
  • 实践:

    • 实现哈希表,处理冲突并优化性能。
    • 实现Trie树,解决前缀匹配问题。

一、哈希表(Hash Table)

1. 哈希表的基本概念

  • 哈希表是一种数据结构,通过键值对(key-value pair)存储数据。
  • 哈希函数将键映射到表中的一个位置(索引)。
  • 哈希表的核心操作
    • 插入(Insert):将键值对插入表中。
    • 查找(Search):根据键查找对应的值。
    • 删除(Delete):根据键删除对应的键值对。

2. 哈希函数

  • 定义:哈希函数接受一个键作为输入,并返回一个整数(哈希值),该整数对应哈希表中的索引位置。
  • 哈希函数设计原则
    • 散列均匀:不同的键应尽量映射到不同的索引。
    • 计算简单:哈希函数应尽量高效。
    • 确定性:相同的键必须始终产生相同的哈希值。

示例

def simple_hash(key, size):
    return key % size

3. 哈希冲突与解决方法

哈希冲突是指不同的键通过哈希函数映射到同一位置。常见的解决方法有:

3.1 拉链法
  • 定义:使用链表存储相同哈希值的所有元素。
  • 优点:简单直观,处理冲突灵活。
  • 缺点:在极端情况下,所有键都映射到同一索引位置,链表退化为线性结构,查找效率降低。

示例

class HashTable:
    def __init__(self, size):
        self.size = size
        self.table = [[] for _ in range(size)]
    
    def hash_function(self, key):
        return key % self.size
    
    def insert(self, key, value):
        index = self.hash_function(key)
        for kvp in self.table[index]:
            if kvp[0] == key:
                kvp[1] = value
                return
        self.table[index].append([key, value])
    
    def get(self, key):
        index = self.hash_function(key)
        for kvp in self.table[index]:
            if kvp[0] == key:
                return kvp[1]
        return None
3.2 开放地址法
  • 定义:在发生冲突时,寻找下一个空闲位置存放键值对。
  • 常见策略
    • 线性探测:从冲突位置开始,依次探测下一个位置。
    • 二次探测:根据二次函数探测新位置,减少聚集效应。
    • 双重散列:使用另一个哈希函数计算步长。

示例(线性探测法):

class HashTable:
    def __init__(self, size):
        self.size = size
        self.table = [None] * size
    
    def hash_function(self, key):
        return key % self.size
    
    def insert(self, key, value):
        index = self.hash_function(key)
        while self.table[index] is not None:
            index = (index + 1) % self.size
        self.table[index] = (key, value)
    
    def get(self, key):
        index = self.hash_function(key)
        while self.table[index] is not None:
            if self.table[index][0] == key:
                return self.table[index][1]
            index = (index + 1) % self.size
        return None

4. 哈希表的应用场景及优化策略

4.1 应用场景
  • 快速查找:如符号表、缓存、数据库索引等。
  • 计数统计:如统计单词频率。
  • 去重:如判断元素是否出现过。
4.2 优化策略
  • 负载因子:控制负载因子(装载因子)在一定范围内(如0.7左右),保持哈希表的性能。
  • 动态扩展:当负载因子过高时,自动扩展哈希表的容量并重新散列。
  • 优化哈希函数:选择散列效果好的哈希函数,减少冲突。

二、Trie树(前缀树)

1. Trie树的基本概念

  • Trie树是一种多叉树,用于高效地存储和查找字符串的前缀。
  • 特点
    • 每个节点代表一个字符。
    • 从根节点到某一节点的路径表示一个字符串的前缀。
    • 叶节点表示一个完整的字符串。

Trie树的结构

          ""
         /  \
       "a"  "b"
       /     \
     "p"     "a"
     /       / \
   "p"     "r" "t"
   /       /
 "l"     "e"
 /         \
"e"       "s"

2. Trie树的实现

Trie树的基本操作

  • 插入:将一个字符串插入Trie树。
  • 查找:判断一个字符串是否在Trie树中。
  • 删除:从Trie树中删除一个字符串。

示例

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_end_of_word = False

class Trie:
    def __init__(self):
        self.root = TrieNode()
    
    def insert(self, word):
        node = self.root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end_of_word = True
    
    def search(self, word):
        node = self.root
        for char in word:
            if char not in node.children:
                return False
            node = node.children[char]
        return node.is_end_of_word
    
    def starts_with(self, prefix):
        node = self.root
        for char in prefix:
            if char not in node.children:
                return False
            node = node.children[char]
        return True

3. Trie树在字符串处理中的应用

  • 前缀匹配:快速查找具有相同前缀的单词,如搜索建议功能。
  • 词频统计:在大量字符串中快速统计某个前缀出现的频率。
  • 字符串排序:通过Trie树对字符串进行字典序排序。

前缀匹配示例

trie = Trie()
words = ["apple", "app", "apex", "bat", "bar", "barn"]
for word in words:
    trie.insert(word)

print(trie.starts_with("ap"))  # True
print(trie.starts_with("ba"))  # True
print(trie.starts_with("cat")) # False

三、实践:实现哈希表与Trie树

1. 实现哈希表

  • 功能
    • 支持插入、查找和删除操作。
    • 处理哈希冲突。
    • 优化性能(如扩展哈希表、动态调整负载因子)。

代码实现

class HashTable:
    def __init__(self, size=10):
        self.size = size
        self.table = [[] for _ in range(size)]
        self.count = 0
        self.load_factor = 0.75
    
    def hash_function(self, key):
        return hash(key) % self.size
    
    def resize(self):
        new_size = self.size * 2
        new_table = [[] for _ in range(new_size)]
        for bucket in self.table:
            for key, value in bucket:
                index = hash(key) % new_size
                new_table[index].append((key, value))
        self.size = new_size
        self.table = new_table
    
    def insert(self, key, value):
        if self.count / self.size > self.load_factor:
            self.resize()
        index = self.hash_function(key)
        for kvp in self.table[index]:
            if kvp[0] == key:
                kvp[1] = value
                return
        self.table[index].append((key, value))
        self.count += 1
    
    def get(self, key):
        index = self.hash_function(key)
        for kvp in self.table[index]:
            if kvp[0] == key:
                return kvp[1]
        return None
    
    def delete(self, key):
        index = self.hash_function(key)
        for i, kvp in enumerate(self.table[index]):
            if kvp[0] == key:
                del self.table[index][i]
                self.count -= 1
                return True
        return False

2. 实现Trie树

  • 功能
    • 支持插入、查找和前缀匹配操作。
    • 用于高效处理字符串集合。

代码实现

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_end_of_word = False

class Trie:
    def __init__(self):
        self.root = TrieNode()
    
    def insert(self, word):
        node = self.root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end_of_word = True
    
    def search(self, word):
        node = self.root
        for char in word:
            if char not in node.children:
                return False
            node = node.children[char]
        return node.is_end_of_word
    
    def starts_with(self, prefix):
        node = self.root
        for char in prefix:
            if char not in node.children:
                return False
            node = node.children[char]
        return True
    
    def delete(self, word):
        def _delete(node, word, depth):
            if depth == len(word):
                if not node.is_end_of_word:
                    return False
                node.is_end_of_word = False
                return len(node.children) == 0
            char = word[depth]
            if char not in node.children:
                return False
            can_delete_child = _delete(node.children[char], word, depth + 1)
            if can_delete_child:
                del node.children[char]
                return len(node.children) == 0
            return False
        
        _delete(self.root, word, 0)

# 使用示例
trie = Trie()
words = ["apple", "app", "apex", "bat", "bar", "barn"]
for word in words:
    trie.insert(word)

# 查找操作
print(trie.search("apple"))  # True
print(trie.search("app"))    # True
print(trie.search("bat"))    # True
print(trie.search("bats"))   # False

# 前缀匹配操作
print(trie.starts_with("ap"))  # True
print(trie.starts_with("ba"))  # True
print(trie.starts_with("cat")) # False

# 删除操作
trie.delete("app")
print(trie.search("app"))    # False
print(trie.search("apple"))  # True

3. 实践总结

  • 哈希表Trie树是常见的数据结构,广泛用于快速数据检索、字符串处理等场景。
  • 哈希表通过哈希函数将键映射到索引位置,处理冲突的方式主要包括拉链法和开放地址法。优化策略包括控制负载因子和动态扩展哈希表。
  • Trie树适合处理前缀匹配问题,可以快速插入、查找和删除字符串,特别在实现自动补全、词频统计等功能时有明显优势。
  • 实践过程中,通过实现哈希表和Trie树,进一步理解了这些数据结构的内部机制和应用场景,为解决实际问题奠定了基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值