7.1 数据结构基础
如何理解基础的数据结构?
基础的数据结构是计算机存储、组织数据的方式。它就像是构建程序大厦的基石,不同的数据结构适用于不同的应用场景,合理选择数据结构能显著提升程序的性能和效率。
- 数组(Array):是最基本的数据结构之一,它是一组相同类型元素的有序集合,元素在内存中连续存储。通过索引可以快速访问数组中的任意元素,但插入和删除操作可能需要移动大量元素,时间复杂度较高。
- 链表(Linked List):由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表的插入和删除操作相对高效,只需修改指针指向,但随机访问元素的效率较低,需要从头节点开始遍历。
- 栈(Stack):遵循后进先出(LIFO)原则的数据结构,就像一摞盘子,最后放上去的盘子最先被拿走。栈的基本操作包括入栈(push)和出栈(pop),常用于实现递归调用、表达式求值等。
- 队列(Queue):遵循先进先出(FIFO)原则的数据结构,类似于排队,先到的人先接受服务。队列的基本操作包括入队(enqueue)和出队(dequeue),常用于任务调度、消息传递等。
- 树(Tree):是一种非线性数据结构,由节点和边组成,每个节点可以有零个或多个子节点。常见的树结构有二叉树、二叉搜索树、平衡二叉树等,树结构常用于表示层次关系,如文件系统、数据库索引等。
- 图(Graph):由顶点和边组成,用于表示对象之间的关系。图可以分为有向图和无向图,常用于社交网络、地图导航等领域。
7.2 算法思想
有哪些常见的算法思想?
- 分治法(Divide and Conquer):将一个复杂的问题分解为若干个规模较小、相互独立且与原问题形式相同的子问题,然后分别解决这些子问题,最后将子问题的解合并得到原问题的解。例如,快速排序、归并排序等算法都采用了分治法的思想。
- 动态规划(Dynamic Programming):通过把原问题分解为相对简单的子问题,并保存子问题的解来避免重复计算,从而解决复杂问题。动态规划通常适用于具有最优子结构和重叠子问题的问题,如背包问题、最长公共子序列问题等。
- 贪心算法(Greedy Algorithm):在每一步选择中都采取当前状态下的最优选择,希望通过局部最优解来达到全局最优解。贪心算法并不一定能得到全局最优解,但在某些问题上可以得到近似最优解,如哈夫曼编码、最小生成树的 Prim 算法和 Kruskal 算法等。
- 回溯算法(Backtracking):是一种深度优先搜索的算法,通过尝试所有可能的解决方案来找到问题的解。当发现当前的选择无法得到有效的解时,会回溯到上一步,尝试其他的选择。回溯算法常用于解决组合问题、排列问题、迷宫问题等。
- 分支限界法(Branch and Bound):与回溯算法类似,也是一种搜索算法,但它通常用于求解最优化问题。分支限界法通过对问题的解空间进行搜索,并使用限界函数来剪去不可能包含最优解的分支,从而提高搜索效率。
7.3 常见排序算法
有哪些常见的排序算法?
- 冒泡排序(Bubble Sort):比较相邻的元素,如果顺序错误就把它们交换过来,重复此步骤直到整个数组有序。时间复杂度为 O(n2),空间复杂度为 O(1)。
- 选择排序(Selection Sort):在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。时间复杂度为 O(n2),空间复杂度为 O(1)。
- 插入排序(Insertion Sort):将未排序数据插入到已排序序列的合适位置。对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。时间复杂度为 O(n2),空间复杂度为 O(1)。
- 希尔排序(Shell Sort):是插入排序的改进版本,它通过将原始数据分成多个子序列来改善插入排序的性能。先将整个待排序的记录序列分割成若干个子序列分别进行直接插入排序,待整个序列中的记录 "基本有序" 时,再对全体记录进行依次直接插入排序。时间复杂度介于 O(n) 和 O(n2) 之间,空间复杂度为 O(1)。
- 归并排序(Merge Sort):采用分治法,将一个数组分成两个子数组,分别对这两个子数组进行排序,然后将排好序的子数组合并成一个最终的有序数组。时间复杂度为 O(nlogn),空间复杂度为 O(n)。
- 快速排序(Quick Sort):同样采用分治法,选择一个基准值,将数组分为两部分,使得左边部分的元素都小于等于基准值,右边部分的元素都大于等于基准值,然后分别对左右两部分进行排序。时间复杂度平均为 O(nlogn),最坏情况下为 O(n2),空间复杂度平均为 O(logn)。
- 堆排序(Heap Sort):利用堆这种数据结构进行排序,将数组构建成一个最大堆(或最小堆),然后依次取出堆顶元素并调整堆,直到堆为空。时间复杂度为 O(nlogn),空间复杂度为 O(1)。
- 计数排序(Counting Sort):适用于整数排序,通过统计每个元素出现的次数,然后根据统计结果将元素放回原数组中。时间复杂度为 O(n+k),其中 k 是数据的范围,空间复杂度为 O(k)。
- 桶排序(Bucket Sort):将数据分到有限数量的桶里,每个桶再分别进行排序(可以使用其他排序算法)。时间复杂度平均为 O(n+k),其中 k 是桶的数量,空间复杂度为 O(n+k)。
- 基数排序(Radix Sort):按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。时间复杂度为 O(d(n+k)),其中 d 是数据的位数,k 是基数,空间复杂度为 O(n+k)。
7.4 大数据处理算法
何谓海量数据处理?解决的思路?
海量数据处理是指对海量数据进行采集、存储、处理和分析的过程。由于数据量巨大,传统的数据处理方法可能无法满足需求,需要采用特殊的算法和技术。
解决海量数据处理问题的常见思路如下:
- 分治思想:将海量数据分割成多个小的数据块,分别对这些小数据块进行处理,最后将处理结果合并。
- 哈希映射(Hash Mapping):通过哈希函数将数据映射到不同的桶中,从而减少数据的规模,便于后续处理。
- 堆(Heap):使用堆来维护数据的前 N 大或前 N 小元素,时间复杂度为 O(nlogN)。
- 布隆过滤器(Bloom Filter):用于判断一个元素是否存在于一个集合中,具有空间效率高的特点,但可能存在一定的误判率。
- 数据库索引:利用数据库的索引技术,如 B - 树、B + 树等,提高数据的查询效率。
- 并行计算:使用多台计算机或多个处理器并行处理数据,提高处理速度。
大数据处理之分治思想?
分治思想是将一个大规模的问题分解为若干个规模较小、相互独立且与原问题形式相同的子问题,然后分别解决这些子问题,最后将子问题的解合并得到原问题的解。在大数据处理中,分治思想常用于以下场景:
- 数据分割:将海量数据分割成多个小的数据块,每个数据块可以在不同的计算机或处理器上并行处理。
- 并行计算:对分割后的数据块进行并行处理,提高处理速度。
- 结果合并:将各个子问题的处理结果合并,得到最终的处理结果。
例如,在对海量数据进行排序时,可以将数据分割成多个小的数据块,分别对这些小数据块进行排序,然后将排好序的小数据块合并成一个最终的有序数组。
海量日志数据,提取出某日访问百度次数最多的那个 IP?
-
思路:首先对海量日志数据进行筛选,提取出某日的日志数据。然后使用哈希表(如 HashMap)统计每个 IP 的访问次数,最后遍历哈希表,找出访问次数最多的 IP。
-
代码示例(Python):
from collections import defaultdict
假设日志数据存储在一个列表中,每个元素是一条日志记录
logs = [
"2025-04-06 12:00:00 192.168.1.100",
"2025-04-06 12:01:00 192.168.1.101",
"2025-04-06 12:02:00 192.168.1.100",
# 更多日志记录...
]ip_count = defaultdict(int)
for log in logs:
date, _, ip = log.split(" ", 2)
if date == "2025-04-06":
ip_count[ip] += 1max_count = 0
most_visited_ip = None
for ip, count in ip_count.items():
if count > max_count:
max_count = count
most_visited_ip = ipprint(f"某日访问百度次数最多的 IP 是: {most_visited_ip},访问次数为: {max_count}")
寻找热门查询,300 万个查询字符串中统计最热门的 10 个查询?
-
思路:使用哈希表(如 HashMap)统计每个查询字符串的出现次数,然后使用最小堆(优先队列)维护出现次数最多的 10 个查询字符串。遍历哈希表,将元素依次加入堆中,如果堆的大小超过 10,则移除堆顶元素(出现次数最少的元素)。
-
代码示例(Python):
import heapq
from collections import defaultdict假设查询字符串存储在一个列表中
queries = [
"query1",
"query2",
"query1",
# 更多查询字符串...
]query_count = defaultdict(int)
for query in queries:
query_count[query] += 1heap = []
for query, count in query_count.items():
if len(heap) < 10:
heapq.heappush(heap, (count, query))
else:
if count > heap[0][0]:
heapq.heappop(heap)
heapq.heappush(heap, (count, query))按出现次数从大到小排序
heap.sort(reverse=True)
print("最热门的 10 个查询:")
for count, query in heap:
print(f"{query}: {count}")
有一个 1G 大小的一个文件,里面每一行是一个词,词的大小不超过 16 字节,内存限制大小是 1M。返回频数最高的 100 个词?
-
思路 :
- 分治:由于文件大小超过内存限制,需要将文件分割成多个小文件。可以使用哈希函数将每个词映射到不同的小文件中,保证相同的词会被映射到同一个小文件中。
- 统计:依次读取每个小文件,使用哈希表统计每个词的出现次数。
- 合并:使用最小堆维护出现次数最多的 100 个词,遍历所有小文件的统计结果,更新堆中的元素。
-
代码示例(Python 伪代码):
import os
import heapq
from collections import defaultdict分割文件
def split_file(input_file, num_files):
file_handles = [open(f"part_{i}.txt", "w") for i in range(num_files)]
with open(input_file, "r") as f:
for line in f:
word = line.strip()
file_index = hash(word) % num_files
file_handles[file_index].write(word + "\n")
for handle in file_handles:
handle.close()统计每个小文件中词的出现次数
def count_words_in_file(file_path):
word_count = defaultdict(int)
with open(file_path, "r") as f:
for line in f:
word = line.strip()
word_count[word] += 1
return word_count合并所有小文件的统计结果,找出出现次数最多的 100 个词
def find_top_100_words(num_files):
heap = []
for i in range(num_files):
file_path = f"part_{i}.txt"
word_count = count_words_in_file(file_path)
for word, count in word_count.items():
if len(heap) < 100:
heapq.heappush(heap, (count, word))
else:
if count > heap[0][0]:
heapq.heappop(heap)
heapq.heappush(heap, (count, word))
# 按出现次数从大到小排序
heap.sort(reverse=True)
return heap主函数
def main():
input_file = "large_file.txt"
num_files = 1000 # 根据内存限制和文件大小调整
split_file(input_file, num_files)
top_100_words = find_top_100_words(num_files)
print("频数最高的 100 个词:")
for count, word in top_100_words:
print(f"{word}: {count}")
# 删除临时文件
for i in range(num_files):
os.remove(f"part_{i}.txt")if name == "main":
main()
海量数据分布在 100 台电脑中,想个办法高效统计出这批数据的 TOP10?
- 思路 :
- 本地统计:每台电脑分别统计本地数据中出现次数最多的 10 个元素。
- 数据合并:将 100 台电脑的统计结果汇总到一台电脑上。
- 全局统计:在汇总电脑上使用最小堆统计出最终的 TOP10。
- 具体步骤 :
- 在每台电脑上,使用哈希表统计本地数据中每个元素的出现次数,然后使用最小堆找出出现次数最多的 10 个元素。
- 将每台电脑的统计结果发送到汇总电脑。
- 在汇总电脑上,将所有统计结果合并,使用最小堆找出最终的 TOP10。
有 10 个文件,每个文件 1G,每个文件的每一行存放的都是用户的 query,每个文件的 query 都可能重复。要求你按照 query 的频度排序?
-
思路 :
- 分治:将每个文件分割成多个小文件,使用哈希函数将相同的 query 映射到同一个小文件中。
- 统计:依次读取每个小文件,使用哈希表统计每个 query 的出现次数。
- 合并:将所有小文件的统计结果合并到一个大的哈希表中。
- 排序:将大哈希表中的元素按照出现次数进行排序。
-
代码示例(Python 伪代码):
import os
from collections import defaultdict分割文件
def split_files(input_files, num_files):
file_handles = [[open(f"part_{i}_{j}.txt", "w") for j in range(num_files)] for i in range(len(input_files))]
for i, input_file in enumerate(input_files):
with open(input_file, "r") as f:
for line in f:
query = line.strip()
file_index = hash(query) % num_files
file_handles[i][file_index].write(query + "\n")
for handles in file_handles:
for handle in handles:
handle.close()统计每个小文件中 query 的出现次数
def count_queries_in_file(file_path):
query_count = defaultdict(int)
with open(file_path, "r") as f:
for line in f:
query = line.strip()
query_count[query] += 1
return query_count合并所有小文件的统计结果
def merge_counts(num_files_per_input, num_input_files):
total_count = defaultdict(int)
for i in range(num_input_files):
for j in range(num_files_per_input):
file_path = f"part_{i}_{j}.txt"
query_count = count_queries_in_file(file_path)
for query, count in query_count.items():
total_count[query] += count
return total_count按频度排序
def sort_queries_by_frequency(query_count):
sorted_queries = sorted(query_count.items(), key=lambda item: item[1], reverse=True)
return sorted_queries主函数
def main():
input_files = [f"file_{i}.txt" for i in range(10)]
num_files_per_input = 100 # 根据内存限制和文件大小调整
split_files(input_files, num_files_per_input)
total_count = merge_counts(num_files_per_input, len(input_files))
sorted_queries = sort_queries_by_frequency(total_count)
print("按频度排序的 queries:")
for query, count in sorted_queries:
print(f"{query}: {count}")
# 删除临时文件
for i in range(len(input_files)):
for j in range(num_files_per_input):
os.remove(f"part_{i}_{j}.txt")if name == "main":
main()
给定 a、b 两个文件,各存放 50 亿个 url,每个 url 各占 64 字节,内存限制是 4G,让你找出 a、b 文件共同的 url?
-
思路 :
- 分治:由于文件大小超过内存限制,需要将文件分割成多个小文件。可以使用哈希函数将每个 url 映射到不同的小文件中,保证相同的 url 会被映射到同一个小文件中。
- 查找:依次读取 a 文件的每个小文件,将其中的 url 存储在哈希表中,然后读取 b 文件对应的小文件,检查每个 url 是否在哈希表中,如果存在,则为共同的 url。
-
代码示例(Python 伪代码):
import os
分割文件
def split_file(input_file, num_files):
file_handles = [open(f"part_{i}.txt", "w") for i in range(num_files)]
with open(input_file, "r") as f:
for line in f:
url = line.strip()
file_index = hash(url) % num_files
file_handles[file_index].write(url + "\n")
for handle in file_handles:
handle.close()查找共同的 url
def find_common_urls(a_files, b_files):
common_urls = set()
for i in range(len(a_files)):
url_set = set()
with open(a_files[i], "r") as f:
for line in f:
url = line.strip()
url_set.add(url)
with open(b_files[i], "r") as f:
for line in f:
url = line.strip()
if url in url_set:
common_urls.add(url)
return common_urls主函数
def main():
a_file = "a.txt"
b_file = "b.txt"
num_files = 1000 # 根据内存限制和文件大小调整
split_file(a_file, num_files)
split_file(b_file, num_files)
a_files = [f"part_{i}.txt" for i in range(num_files)]
b_files = [f"part_{i}.txt" for i in range(num_files)]
common_urls = find_common_urls(a_files, b_files)
print("共同的 url:")
for url in common_urls:
print(url)
# 删除临时文件
for i in range(num_files):
os.remove(f"part_{i}.txt")if name == "main":
main()
怎么在海量数据中找出重复次数最多的一个?
-
思路:使用哈希表(如 HashMap)统计每个元素的出现次数,同时记录出现次数最多的元素及其出现次数。遍历完所有数据后,即可得到重复次数最多的元素。
-
代码示例(Python):
from collections import defaultdict
假设数据存储在一个列表中
data = [
1, 2, 3, 1, 2, 1,
# 更多数据...
]element_count = defaultdict(int)
max_count = 0
most_repeated_element = None
for element in data:
element_count[element] += 1
if element_count[element] > max_count:
max_count = element_count[element]
most_repeated_element = elementprint(f"重复次数最多的元素是: {most_repeated_element},重复次数为: {max_count}")
上千万或上亿数据 (有重复),统计其中出现次数最多的前 N 个数据?
-
思路:使用哈希表(如 HashMap)统计每个元素的出现次数,然后使用最小堆(优先队列)维护出现次数最多的前 N 个元素。遍历哈希表,将元素依次加入堆中,如果堆的大小超过 N,则移除堆顶元素(出现次数最少的元素)。
-
代码示例(Python):
import heapq
from collections import defaultdict假设数据存储在一个列表中
data = [
1, 2, 3, 1, 2, 1,
# 更多数据...
]element_count = defaultdict(int)
for element in data:
element_count[element] += 1N = 10 # 统计前 10 个出现次数最多的元素
heap = []
for element, count in element_count.items():
if len(heap) < N:
heapq.heappush(heap, (count, element))
else:
if count > heap[0][0]:
heapq.heappop(heap)
heapq.heappush(heap, (count, element))按出现次数从大到小排序
heap.sort(reverse=True)
print(f"出现次数最多的前 {N} 个数据:")
for count, element in heap:
print(f"{element}: {count}")
一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前 10 个词,请给出思想,给出时间复杂度分析?
- 思路 :
- 读取文本文件,使用哈希表(如 HashMap)统计每个词的出现次数。
- 使用最小堆(优先队列)维护出现次数最多的前 10 个词。
- 遍历哈希表,将元素依次加入堆中,如果堆的大小超过 10,则移除堆顶元素(出现次数最少的元素)。
- 时间复杂度分析 :
- 读取文件并统计词的出现次数:O(n),其中 n 是文件的行数。
- 维护最小堆:每次插入和删除操作的时间复杂度为 O(logk),其中 k 是堆的大小(这里 k=10),总共需要进行 n 次操作,因此时间复杂度为 O(nlogk)。
- 总的时间复杂度为 O(n+nlogk)=O(nlogk)。
一个文本文件,找出前 10 个经常出现的词,但这次文件比较长,说是上亿行或十亿行,总之无法一次读入内存,问最优解?
- 思路 :
- 分治:将文件分割成多个小文件,使用哈希函数将相同的词映射到同一个小文件中。
- 统计:依次读取每个小文件,使用哈希表统计每个词的出现次数。
- 合并:使用最小堆维护出现次数最多的前 10 个词,遍历所有小文件的统计结果,更新堆中的元素。
- 时间复杂度分析 :
- 分割文件:O(n),其中 n 是文件的行数。
- 统计每个小文件中词的出现次数:O(n)。
- 合并所有小文件的统计结果:O(nlogk),其中 k 是堆的大小(这里 k=10)。
- 总的时间复杂度为 O(n+n+nlogk)=O(nlogk)。
100w 个数中找出最大的 100 个数?
-
思路:使用最小堆(优先队列)维护最大的 100 个数。遍历 100w 个数,将元素依次加入堆中,如果堆的大小超过 100,则移除堆顶元素(当前最小的元素)。
-
代码示例(Python):
import heapq
import random生成 100w 个数
data = [random.randint(1, 1000000) for _ in range(1000000)]
N = 100 # 找出最大的 100 个数
heap = []
for num in data:
if len(heap) < N:
heapq.heappush(heap, num)
else:
if num > heap[0]:
heapq.heappop(heap)
heapq.heappush(heap, num)按从大到小排序
heap.sort(reverse=True)
print("最大的 100 个数:")
for num in heap:
print(num)
5 亿个 int 找它们的中位数?
-
思路 :
- 分治:将 5 亿个 int 分成多个小文件,每个小文件可以读入内存。
- 排序:对每个小文件进行排序。
- 合并:使用归并排序的思想,将所有小文件合并成一个有序的大文件。
- 查找中位数:根据大文件的长度,找出中位数。
-
代码示例(Python 伪代码):
import os
分割文件
def split_file(input_file, num_files):
file_handles = [open(f"part_{i}.txt", "w") for i in range(num_files)]
with open(input_file, "r") as f:
for line in f:
num = int(line.strip())
file_index = hash(num) % num_files
file_handles[file_index].write(str(num) + "\n")
for handle in file_handles:
handle.close()对每个小文件进行排序
def sort_files(num_files):
for i in range(num_files):
file_path = f"part_{i}.txt"
nums = []
with open(file_path, "r") as f:
for line in f:
num = int(line.strip())
nums.append(num)
nums.sort()
with open(file_path, "w") as f:
for num in nums:
f.write(str(num) + "\n")合并所有小文件
def merge_files(num_files):
file_handles = [open(f"part_{i}.txt", "r") for i in range(num_files)]
pointers = [0] * num_files
num_counts = []
for i in range(num_files):
with open(f"part_{i}.txt", "r") as f:
num_counts.append(len(f.readlines()))
result = []
while True:
min_num = float('inf')
min_index = -1
for i in range(num_files):
if pointers[i] < num_counts[i]:
file_handles[i].seek(pointers[i] * 10) # 假设每个整数占 10 个字节
num = int(file_handles[i].readline().strip())
if num < min_num:
min_num = num
min_index = i
if min_index == -1:
break
result.append(min_num)
pointers[min_index] += 1
for handle in file_handles:
handle.close()
return result查找中位数
def find_median(nums):
n = len(nums)
if n % 2 == 1:
return nums[n // 2]
else:
return (nums[n // 2 - 1] + nums[n // 2]) / 2主函数
def main():
input_file = "large_file.txt"
num_files = 1000 # 根据内存限制和文件大小调整
split_file(input_file, num_files)
sort_files(num_files)
sorted_nums = merge_files(num_files)
median = find_median(sorted_nums)
print(f"中位数是: {median}")
# 删除临时文件
for i in range(num_files):
os.remove(f"part_{i}.txt")if name == "main":
main()
在 2.5 亿个整数中找出不重复的整数,注,内存不足以容纳这 2.5 亿个整数。
-
思路 :
- 分治:将 2.5 亿个整数分成多个小文件,使用哈希函数将相同的整数映射到同一个小文件中。
- 统计:依次读取每个小文件,使用哈希表统计每个整数的出现次数。
- 筛选:遍历哈希表,找出出现次数为 1 的整数,即为不重复的整数。
-
代码示例(Python 伪代码):
import os
from collections import defaultdict分割文件
def split_file(input_file, num_files):
file_handles = [open(f"part_{i}.txt", "w") for i in range(num_files)]
with open(input_file, "r") as f:
for line in f:
num = int(line.strip())
file_index = hash(num) % num_files
file_handles[file_index].write(str(num) + "\n")
for handle in file_handles:
handle.close()统计每个小文件中整数的出现次数
def count_nums_in_file(file_path):
num_count = defaultdict(int)
with open(file_path, "r") as f:
for line in f:
num = int(line.strip())
num_count[num] += 1
return num_count筛选出不重复的整数
def find_unique_nums(num_files):
unique_nums = set()
for i in range(num_files):
file_path = f"part_{i}.txt"
num_count = count_nums_in_file(file_path)
for num, count in num_count.items():
if count == 1:
unique_nums.add(num)
return unique_nums主函数
def main():
input_file = "large_file.txt"
num_files = 1000 # 根据内存限制和文件大小调整
split_file(input_file, num_files)
unique_nums = find_unique_nums(num_files)
print("不重复的整数:")
for num in unique_nums:
print(num)
# 删除临时文件
for i in range(num_files):
os.remove(f"part_{i}.txt")if name == "main":
main()
给 40 亿个不重复的 unsigned int 的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那 40 亿个数当中?
-
思路:使用位图(Bitmap)来存储这 40 亿个不重复的 unsigned int 整数。一个 unsigned int 占用 4 个字节,即 32 位,40 亿个 unsigned int 最多需要 40×108/32=125×106 字节,约 125MB 的内存。
-
代码示例(Python):
class Bitmap:
def init(self, size):
self.size = size
self.bitmap = [0] * ((size >> 5) + 1)def set_bit(self, num): index = num >> 5 offset = num & 0x1F self.bitmap[index] |= (1 << offset) def get_bit(self, num): index = num >> 5 offset = num & 0x1F return (self.bitmap[index] & (1 << offset)) != 0
假设 40 亿个不重复的 unsigned int 整数存储在一个列表中
data = [
1, 2, 3, 5, 7,
# 更多数据...
]创建位图
bitmap = Bitmap(2**32)
for num in data:
bitmap.set_bit(num)要判断的数
target_num = 5
if bitmap.get_bit(target_num):
print(f"{target_num} 在这 40 亿个数当中。")
else:
print(f"{target_num} 不在这 40 亿个数当中。")
7.5 加密算法
什么是摘要算法?有哪些?
摘要算法,也被叫做哈希算法或者散列算法,它能把任意长度的输入数据通过特定的算法转换为固定长度的输出,这个输出被称作摘要或者哈希值。摘要算法具备以下特性:
- 确定性:相同的输入必定会得到相同的输出。
- 高效性:能快速地计算出摘要。
- 雪崩效应:输入数据哪怕只有微小的改变,输出的摘要也会有极大不同。
- 不可逆性:没办法从摘要还原出原始输入数据。
常见的摘要算法如下:
- MD5(Message - Digest Algorithm 5):产生 128 位的哈希值,曾经广泛使用,但现在发现存在安全漏洞,容易遭受碰撞攻击,即不同的输入可能产生相同的输出,所以在安全要求高的场景中不再适用。
- SHA - 1(Secure Hash Algorithm 1):输出 160 位的哈希值,安全性也低于现在的标准,也存在碰撞问题,逐渐被弃用。
- SHA - 2(Secure Hash Algorithm 2):是一个哈希函数族,包含了不同的哈希算法,如 SHA - 224、SHA - 256、SHA - 384 和 SHA - 512 等,分别产生 224 位、256 位、384 位和 512 位的哈希值。目前,SHA - 2 在很多场景中被广泛使用。
- SHA - 3(Secure Hash Algorithm 3):是新一代的哈希算法,为应对 SHA - 1 和 SHA - 2 可能存在的潜在威胁而设计,具有良好的安全性和性能。
什么是加密算法?有哪些?
加密算法是用于对数据进行加密和解密的算法,其目的是保护数据的机密性、完整性和可用性。加密算法可分为对称加密算法和非对称加密算法。
对称加密算法
加密和解密使用相同密钥的算法。其优点是加密和解密速度快,效率高;缺点是密钥管理困难,一旦密钥泄露,数据就会面临安全风险。常见的对称加密算法有:
- DES(Data Encryption Standard):是一种经典的对称加密算法,密钥长度为 56 位。由于密钥长度较短,现在已经被认为不够安全,逐渐被弃用。
- 3DES(Triple DES):是对 DES 的改进,通过多次使用 DES 算法来增加密钥长度和安全性,通常使用 3 个不同的 56 位密钥,有效密钥长度达到 168 位。
- AES(Advanced Encryption Standard):是目前应用最广泛的对称加密算法,支持 128 位、192 位和 256 位的密钥长度。AES 具有高效、安全等优点,被广泛应用于各种领域。
非对称加密算法
使用一对密钥,即公钥和私钥。公钥可以公开,用于加密数据;私钥必须保密,用于解密数据。非对称加密算法的优点是密钥管理相对简单,安全性较高;缺点是加密和解密速度较慢。常见的非对称加密算法有:
- RSA:基于大整数分解难题,是最早也是最广泛使用的非对称加密算法之一。RSA 算法可用于加密和数字签名,密钥长度一般为 1024 位、2048 位或更高。
- ECC(Elliptic Curve Cryptography):基于椭圆曲线离散对数难题,与 RSA 相比,在相同的安全级别下,ECC 所需的密钥长度更短,因此具有更高的效率和更小的密钥存储空间。
什么是国密算法?有哪些?
国密算法即国家密码管理局制定的一系列商用密码算法,是我国自主研发的加密算法,在保障国家信息安全方面发挥着重要作用。常见的国密算法如下:
- SM1:是一种对称加密算法,其加密强度与 AES 相当,但算法细节未公开,以硬件加密的形式实现,主要应用于金融领域的安全芯片。
- SM2:属于非对称加密算法,基于椭圆曲线密码体制,与 RSA 算法相比,具有更高的安全性和更小的密钥尺寸。SM2 可用于数字签名、密钥交换和加密等场景。
- SM3:是一种摘要算法,输出 256 位的哈希值,具有较高的安全性和性能,可用于数字签名、消息认证等领域。
- SM4:是一种对称加密算法,密钥长度为 128 位,分组长度也为 128 位。SM4 算法的安全性和性能与 AES 相当,广泛应用于各种信息系统的加密保护。
- SM9:是基于标识的密码算法,解决了传统公钥密码体制中证书管理的复杂性问题,可用于数字签名、密钥交换和加密等场景。