一、哈希表
1.1 什么是哈希表
哈希表是一种根据键(Key) 直接访问数据的数据结构。它通过哈希函数把键映射到一个下标,然后直接在该位置存取数据。
1.2 为什么用哈希表
| 数据结构 | 查找元素 |
|---|---|
| 数组 | O(n)(遍历) |
| 有序数组 | O(log n)(二分查找) |
| 链表 | O(n) |
| 二叉搜索树 | O(log n) |
| 哈希表 | O(1)(近乎常数时间) |
哈希表的查找速度非常快,和元素数量多少关系不大。
1.3 哈希冲突
不同数据经过哈希函数映射后得到相同的键值,就叫哈希冲突。
解决哈希冲突的常用方法:
-
链地址法:每个哈希桶里挂一个链表,冲突的数据放在链表里
-
开放地址法:如果当前位置被占了,就往后找空位
text
链地址法示例:
索引0 → [数据A] → [数据B] ← A和B冲突了,串成链表
索引1 → [数据C]
索引2 → NULL
索引3 → [数据D] → [数据E] → [数据F]
二、排序算法
2.1 排序算法对比
| 算法 | 平均时间复杂度 | 最坏情况 | 稳定性 | 特点 |
|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | 稳定 | 相邻比较,大数后移 |
| 选择排序 | O(n²) | O(n²) | 不稳定 | 每轮选最小放前面 |
| 插入排序 | O(n²) | O(n²) | 稳定 | 将元素插入有序部分 |
| 希尔排序 | O(n log n) | O(n²) | 不稳定 | 分组+插入排序 |
| 快速排序 | O(n log n) | O(n²) | 不稳定 | 分治,选基准值分组 |
2.2 冒泡排序
相邻两个元素比较,大的往后移。每轮结束当前最大的数就"沉"到了最后面。
c
void BubbleSort(int a[], int len)
{
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
}
2.3 选择排序
每轮从剩下的元素里找到最小的,放到前面。
c
void SelectionSort(int a[], int len)
{
for (int i = 0; i < len - 1; i++) {
int min = i;
for (int j = i + 1; j < len; j++) {
if (a[j] < a[min]) {
min = j;
}
}
if (min != i) {
int tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
}
2.4 插入排序
把数组分成"已排序"和"未排序"两部分,从未排序部分取元素插入到已排序部分的正确位置。
c
void InsertionSort(int a[], int len)
{
for (int i = 1; i < len; i++) {
int key = a[i];
int j = i - 1;
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;
}
}
2.5 希尔排序
插入排序的改进版。先把数据按步长分组,每组分别做插入排序,步长逐步缩小,最后步长为1时做最后一次插入排序。
c
void ShellSort(int a[], int len)
{
for (int gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {
int key = a[i];
int j = i - gap;
while (j >= 0 && a[j] > key) {
a[j + gap] = a[j];
j -= gap;
}
a[j + gap] = key;
}
}
}
2.6 快速排序
核心思想是分治。选一个基准值,把比它小的放左边、比它大的放右边,然后递归对左右两边做同样的操作。
c
int Partition(int a[], int low, int high)
{
int key = a[low];
while (low < high) {
while (low < high && a[high] >= key) high--;
a[low] = a[high];
while (low < high && a[low] <= key) low++;
a[high] = a[low];
}
a[low] = key;
return low;
}
void QuickSort(int a[], int low, int high)
{
if (low < high) {
int mid = Partition(a, low, high);
QuickSort(a, low, mid - 1);
QuickSort(a, mid + 1, high);
}
}
三、今日总结
今天学了哈希表 和排序算法,核心要点如下:
哈希表:
-
通过哈希函数把键映射到存储位置
-
查找时间复杂度接近 O(1)
-
哈希冲突用链地址法或开放地址法解决
排序算法:
-
冒泡排序:相邻比较,大数后移 → O(n²),稳定
-
选择排序:每轮选最小放前面 → O(n²),不稳定
-
插入排序:元素插入有序部分 → O(n²),稳定
-
希尔排序:分组插入排序 → O(n log n),不稳定
-
快速排序:分治,选基准值分组 → O(n log n),不稳定
今日感悟:
哈希表用空间换时间,多占点内存,换来接近瞬时的查找速度。
不同场景适用不同的算法,数据量小、要求稳定,用插入排序;数据量大、追求速度,用快速排序。