复习——栈、队列、树、哈希表

栈、队列、树、哈希表

一、栈(Stack)

1.1 基本概念

定义 :限定仅在表尾 进行插入和删除操作的线性表

特性

  • 先进后出(FILO)

  • 后进先出(LIFO)

核心概念

  • 栈顶(Top):允许操作的一端

  • 栈底(Bottom):不允许操作的一端

  • 入栈(Push):向栈顶添加元素

  • 出栈(Pop):从栈顶移除元素

1.2 数据结构栈 vs 系统栈

对比项 数据结构栈 系统栈(调用栈)
存储位置 堆空间 内存固定区域(约8M)
内容 用户数据 函数调用、局部变量、参数
大小 可自定义 有限制
实现 数组/链表 硬件/OS支持

1.3 实现方式

顺序栈(数组实现)
复制代码
#define MAXSIZE 100
typedef struct {
    int data[MAXSIZE];
    int top;  // 栈顶指针
} SeqStack;
链栈(链表实现)
复制代码
typedef struct StackNode {
    int data;
    struct StackNode *next;
} StackNode;

typedef struct {
    StackNode *top;  // 栈顶指针
    int size;        // 栈大小
} LinkStack;

1.4 基本操作

复制代码
// 初始化
void InitStack(SeqStack *S) {
    S->top = -1;
}

// 入栈
int Push(SeqStack *S, int x) {
    if (S->top == MAXSIZE-1) return 0; // 栈满
    S->data[++S->top] = x;
    return 1;
}

// 出栈
int Pop(SeqStack *S, int *x) {
    if (S->top == -1) return 0; // 栈空
    *x = S->data[S->top--];
    return 1;
}

1.5 应用场景

  1. 函数调用栈:保存调用现场

  2. 表达式求值:中缀转后缀

  3. 括号匹配:检查嵌套正确性

  4. 递归实现:转化为非递归

  5. DFS算法:路径记录与回溯

二、队列(Queue)

2.1 基本概念

定义 :只允许在队尾 插入,在队头删除的线性表

特性:先进先出(FIFO)

核心概念

  • 队头(Front):允许删除的一端

  • 队尾(Rear):允许插入的一端

2.2 实现方式

循环队列(顺序实现)
复制代码
#define MAXSIZE 100
typedef struct {
    int data[MAXSIZE];
    int front;  // 队头指针
    int rear;   // 队尾指针
} CircularQueue;

// 判空:front == rear
// 判满:(rear + 1) % MAXSIZE == front
链式队列
复制代码
typedef struct QueueNode {
    int data;
    struct QueueNode *next;
} QueueNode;

typedef struct {
    QueueNode *front;  // 队头指针
    QueueNode *rear;   // 队尾指针
    int size;
} LinkQueue;

2.3 基本操作

复制代码
// 入队(循环队列)
int EnQueue(CircularQueue *Q, int x) {
    if ((Q->rear + 1) % MAXSIZE == Q->front)
        return 0; // 队满
    Q->data[Q->rear] = x;
    Q->rear = (Q->rear + 1) % MAXSIZE;
    return 1;
}

// 出队
int DeQueue(CircularQueue *Q, int *x) {
    if (Q->front == Q->rear)
        return 0; // 队空
    *x = Q->data[Q->front];
    Q->front = (Q->front + 1) % MAXSIZE;
    return 1;
}

2.4 应用场景

  1. 任务调度:CPU进程调度

  2. 缓冲区:打印机任务队列

  3. BFS算法:图的广度优先搜索

  4. 消息队列:系统间通信

  5. 数据流处理:生产者-消费者模式

三、树(Tree)

3.1 基本概念

定义:n(n≥0)个节点的有限集合

  • n=0:空树

  • n>0:有且仅有一个根节点,其余分为m个互不相交的子树

重要术语

  • 节点的度:子树的个数

  • 叶子节点:度为0的节点

  • 树的度:树中最大的节点度数

  • 节点的层次:根为第1层

  • 树的高度:最大层次

3.2 二叉树(Binary Tree)

定义:每个节点最多有两个子树的树结构

特殊二叉树
  1. 满二叉树

    • 所有层都达到最大节点数

    • 深度为k,节点数=2^k - 1

  2. 完全二叉树

    • 除最后一层外都是满的

    • 最后一层节点集中在左边

二叉树性质
  1. 第i层最多有 2^(i-1) 个节点

  2. 深度为k的二叉树最多有 2^k - 1 个节点

  3. 叶子节点数 = 度为2的节点数 + 1

  4. n个节点的完全二叉树深度 = ⌊log₂n⌋ + 1

3.3 遍历方式

深度优先遍历(DFS)
复制代码
// 先序遍历:根->左->右
void PreOrder(TreeNode *root) {
    if (root == NULL) return;
    visit(root);
    PreOrder(root->left);
    PreOrder(root->right);
}

// 中序遍历:左->根->右
void InOrder(TreeNode *root) {
    if (root == NULL) return;
    InOrder(root->left);
    visit(root);
    InOrder(root->right);
}

// 后序遍历:左->右->根
void PostOrder(TreeNode *root) {
    if (root == NULL) return;
    PostOrder(root->left);
    PostOrder(root->right);
    visit(root);
}
广度优先遍历(层序遍历)
复制代码
void LevelOrder(TreeNode *root) {
    if (root == NULL) return;
    
    TreeNode *queue[MAXSIZE];
    int front = 0, rear = 0;
    queue[rear++] = root;
    
    while (front < rear) {
        TreeNode *node = queue[front++];
        visit(node);
        
        if (node->left) queue[rear++] = node->left;
        if (node->right) queue[rear++] = node->right;
    }
}

3.4 存储结构

顺序存储(数组)

适用于完全二叉树

复制代码
// 下标从1开始
// 节点i的父节点:i/2
// 左孩子:2*i,右孩子:2*i+1
链式存储(二叉链表)
复制代码
typedef struct BiTNode {
    int data;
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

3.5 树的应用

  1. 文件系统:目录结构

  2. 数据库索引:B树、B+树

  3. 决策树:机器学习

  4. 语法分析树:编译器

  5. 家谱图:层次关系

四、哈希表(Hash Table)

4.1 基本概念

定义:通过哈希函数将关键字映射到表中位置的数据结构

核心思想:存储位置 = f(key)

目标:实现O(1)的平均查找时间

4.2 哈希函数设计

方法 公式 特点
直接定址 h(key) = a×key + b 简单,无冲突
除留余数 h(key) = key % p 最常用
平方取中 取key²的中间几位 分布均匀
折叠法 分割相加 适合长关键字

4.3 冲突解决方法

开放定址法
复制代码
// 线性探测:hᵢ(key) = (h(key) + i) % m
// 二次探测:hᵢ(key) = (h(key) ± i²) % m
// 双重散列:hᵢ(key) = (h₁(key) + i×h₂(key)) % m
链地址法(最常用)
复制代码
typedef struct HashNode {
    int key;
    int value;
    struct HashNode *next;
} HashNode;

typedef struct {
    HashNode **table;
    int size;
    int count;
} HashMap;

4.4 性能指标

装载因子

α = 表中元素个数 / 哈希表长度

  • 通常保持 α < 0.75
平均查找长度(ASL)
方法 ASL成功(平均) ASL失败(平均)
线性探测 (1+1/(1-α)²)/2 (1+1/(1-α))/2
链地址法 1+α/2 α+e⁻α

4.5 基本操作实现

复制代码
// 链地址法实现
HashMap* CreateHashMap(int size) {
    HashMap *hm = (HashMap*)malloc(sizeof(HashMap));
    hm->table = (HashNode**)calloc(size, sizeof(HashNode*));
    hm->size = size;
    hm->count = 0;
    return hm;
}

int HashFunction(int key, int size) {
    return abs(key) % size;
}

void HashMapPut(HashMap *hm, int key, int value) {
    int index = HashFunction(key, hm->size);
    
    // 查找是否已存在
    HashNode *node = hm->table[index];
    while (node) {
        if (node->key == key) {
            node->value = value;  // 更新
            return;
        }
        node = node->next;
    }
    
    // 新建节点,头插法
    HashNode *newNode = (HashNode*)malloc(sizeof(HashNode));
    newNode->key = key;
    newNode->value = value;
    newNode->next = hm->table[index];
    hm->table[index] = newNode;
    hm->count++;
}

int HashMapGet(HashMap *hm, int key) {
    int index = HashFunction(key, hm->size);
    HashNode *node = hm->table[index];
    
    while (node) {
        if (node->key == key)
            return node->value;
        node = node->next;
    }
    
    return -1;  // 未找到
}

4.6 应用场景

  1. 快速查找:字典、缓存

  2. 数据去重:统计唯一值

  3. 数据库索引:加速查询

  4. 密码存储:存储哈希值

  5. 路由表:网络路由器

五、四种数据结构对比总结

特性 队列 哈希表
访问方式 栈顶访问 队头访问 多种遍历 直接访问
插入位置 栈顶 队尾 指定位置 哈希位置
删除位置 栈顶 队头 指定位置 任意位置
时间复杂度 O(1) O(1) 遍历O(n) 平均O(1)
空间效率 中等 较低
主要应用 函数调用 任务调度 层次关系 快速查找

六、学习建议与常见问题

6.1 栈的注意事项

  • 栈溢出:递归深度过大或栈空间不足

  • 括号匹配:注意不同括号的优先级

  • 表达式求值:运算符优先级处理

6.2 队列的注意事项

  • 循环队列判空/满:注意判断条件

  • 假溢出:顺序队列的问题

  • 队列大小:合理设置初始大小

6.3 树的注意事项

  • 平衡性:树不平衡会影响性能

  • 遍历顺序:不同遍历的应用场景

  • 存储方式:根据需求选择合适结构

6.4 哈希表的注意事项

  • 哈希函数设计:影响性能的关键

  • 冲突处理:选择合适的解决方法

  • 装载因子:及时扩容避免性能下降

  • 内存管理:链地址法的节点释放


七、综合应用示例

7.1 计算器(栈应用)

复制代码
int calculate(char* s) {
    int stack[MAXSIZE], top = -1;
    int num = 0, res = 0;
    char sign = '+';
    
    for (int i = 0; s[i]; i++) {
        if (isdigit(s[i])) {
            num = num * 10 + (s[i] - '0');
        }
        
        if ((!isdigit(s[i]) && s[i] != ' ') || i == strlen(s)-1) {
            switch(sign) {
                case '+': stack[++top] = num; break;
                case '-': stack[++top] = -num; break;
                case '*': stack[top] *= num; break;
                case '/': stack[top] /= num; break;
            }
            sign = s[i];
            num = 0;
        }
    }
    
    while (top != -1) {
        res += stack[top--];
    }
    return res;
}

7.2 LRU缓存(哈希表+双向链表)

复制代码
// 实现O(1)的get和put操作
// 使用哈希表快速查找,双向链表维护访问顺序

这份笔记涵盖了栈、队列、树和哈希表的核心知识点。建议您:

  1. 理解每种数据结构的特点和适用场景

  2. 掌握基本操作的实现方法

  3. 多做练习题,特别是综合应用题目

  4. 在实际项目中尝试应用这些数据结构

相关推荐
xian_wwq1 小时前
【学习笔记】可信工业数据空间的系统架构
笔记·学习
橘子真甜~1 小时前
C/C++ Linux网络编程10 - http协议
linux·服务器·网络·c++·网络协议·http
jtymyxmz1 小时前
《Maya 2024 超级学习手册》2.3.7 实例:制作玩具蚂蚁模型
学习·maya
碧海银沙音频科技研究院1 小时前
基于物奇wq7036与恒玄bes2800智能眼镜设计
arm开发·人工智能·深度学习·算法·分类
一 乐1 小时前
高校评教|基于SpringBoot+vue高校学生评教系统 (源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
解局易否结局1 小时前
SecretFlow 社区MOOC学习笔记
学习
zimoyin2 小时前
WSL音频转发配置流程:WSL2/WSL1全适配
linux·音视频·wsl·虚拟机·ekho
小白程序员成长日记2 小时前
2025.12.03 力扣每日一题
算法·leetcode·职场和发展
2401_853448232 小时前
busybox制作根文件系统
linux·busybox·系统移植