数组:最基础的存储方式
数组就像一排整齐的储物柜,每个格子都有编号,从0开始依次排列。你要存东西或者取东西,只要知道编号就能直接操作。这种随机访问特性让数组在查找时非常快。
但插入和删除就不太方便了。比如你想在中间加一个元素,就得把后面的全部往后挪一位,相当于重新整理柜子。删除也一样,空出来的位置得补上。
int arr[5] = {10, 20, 30, 40, 50};
// 访问第三个元素
int value = arr[2]; // 得到30在C语言中这样定义一个固定大小的整型数组,简单直接,适合数据量固定、频繁读取的场景。
链表:灵活的动态结构
链表更像是火车车厢,每节车厢装着数据,还连着下一站的方向指引(指针)。你不能直接跳到第5节,必须从车头开始一节节找过去。
但它的好处是增删特别灵活。想加一节?找到位置接上就行。想拆掉一节?改一下前后连接就好了,不用搬动其他部分。
struct ListNode {
int data;
struct ListNode* next;
};
// 创建新节点
struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->data = 100;
node->next = NULL;这种结构常用于实现队列、浏览器历史记录这类经常变动的数据集合。
栈:后进先出的典型代表
栈就像自助餐厅的托盘架,压下去一个,拿出来的时候最先拿的是最上面那个。最后进入的元素最先被取出,也就是LIFO(Last In First Out)。
它只有两个主要操作:入栈(push)和出栈(pop),所有操作都在顶部进行。
# 使用数组模拟栈
int stack[100];
int top = -1;
// 入栈
stack[++top] = 25;
// 出栈
int val = stack[top--];函数调用背后的机制就是靠栈来管理的,每次调用新函数就压入栈帧,执行完再弹出。
队列:排队办事的模型
队列和现实生活中的排队完全一样。先来的先处理,后来的排在后面,遵循FIFO(First In First Out)原则。
常见的应用场景有打印任务调度、消息队列系统等。
typedef struct {
int items[100];
int front;
int rear;
} Queue;
void enqueue(Queue* q, int value) {
q->items[q->rear++] = value;
}前端负责取出,后端负责加入,像地铁站的闸机口,进站口不断有人进来,出站口按顺序离开。
哈希表:快速查找的秘密武器
如果你有一千本书要找,一本本翻太慢。哈希表的做法是给每本书编个唯一编号,然后按编号放到对应格子里。下次想找哪本,算一下编号直接去拿。
这个“编号”叫哈希值,通过哈希函数计算得出。理想情况下,查找时间接近O(1),也就是常数时间。
int hash(int key) {
return key % TABLE_SIZE;
}不过可能会出现冲突——两个不同的键算出了同一个位置。解决办法有链地址法(拉链法)或开放寻址法。实际开发中,Python的字典、Java的HashMap都是基于哈希表实现的。