楼层: 首页/ 软件技术/ C 语言/ 数据结构实战:用 C 手撸一遍
11

数据结构实战:用 C 手撸一遍

Linked List · Stack · Queue · Tree

C 没有现成的 list、map(那是 C++ STL、Python 标准库的事),所以数据结构得自己拿 struct + 指针 + malloc 拼。别嫌麻烦——这一遍拼下来,你才算真的懂了"链表是怎么连起来的"。下面给最核心的单链表。

单链表:节点 + 指针

每个节点装一个数据,外加一个指向下一个节点的指针。最后一个指向 NULL 表示"到头了"。

单链表:创建头节点、头插、遍历、释放

#include <stdio.h> #include <stdlib.h> // 一个链表节点 typedef struct Node { int data; struct Node *next; // 指向下一个节点,自己引用自己,必须用 struct Node* } Node; // 在链表头部插入一个新节点 Node *push_front(Node *head, int val) { Node *n = (Node *)malloc(sizeof(Node)); n->data = val; n->next = head; // 新节点指向原来的头 return n; // 新节点变成新的头,返回它 } // 从头到尾遍历打印 void print_list(Node *head) { for (Node *p = head; p != NULL; p = p->next) { printf("%d -> ", p->data); } printf("NULL\n"); } int main() { Node *head = NULL; // 空链表 head = push_front(head, 30); head = push_front(head, 20); head = push_front(head, 10); // 链表:10->20->30 print_list(head); // 10 -> 20 -> 30 -> NULL // 别忘了释放整段链表,否则全泄漏 while (head) { Node *tmp = head->next; free(head); head = tmp; } return 0; }

运行结果

10 -> 20 -> 30 -> NULL

栈、队列、二叉树:一句话思路

结构怎么实现
栈 stack"后进先出"。用数组 + 一个 top 下标:压栈 a[top++]=x,弹栈 x=a[--top]。
队列 queue"先进先出"。用数组 + 头尾两个下标,或用链表。排队买票,先来的先走。
二叉树每个节点有左、右两个孩子指针。前/中/后序遍历天然就是递归:visit(root->left)、visit(root)、visit(root->right)。
哈希表用一个数组当"桶",key 经过哈希函数算出桶号,同一个桶里挂一条链表(链地址法)。

二叉树的递归遍历(三行核心)

typedef struct TNode { int val; struct TNode *left, *right; } TNode; // 中序遍历:左 -> 根 -> 右 void inorder(TNode *root) { if (root == NULL) return; // 终止条件:空树 inorder(root->left); // 先逛左子树 printf("%d ", root->val); // 再处理自己 inorder(root->right); // 最后逛右子树 }

二叉搜索树(BST)与二分查找

普通二叉树只是"能遍历",二叉搜索树(BST)加了一条规矩:左子树所有值 < 根 < 右子树所有值。于是查找、插入都能每次砍掉一半,平均 O(log n)——比链表挨个找快得多。

BST 插入与查找:递归版,每次往左或右砍一半

BST 节点 + 查找 + 插入(递归核心)

typedef struct Node { int val; struct Node *left, *right; } Node; // 查找:在 root 这棵树里找 key Node* search(Node *root, int key) { if (root == NULL || root->val == key) return root; // 空 或 命中 if (key < root->val) return search(root->left, key); // 比根小,去左子树 else return search(root->right, key); // 比根大,去右子树 } // 插入:递归找到空位置挂上去(返回新根) Node* insert(Node *root, int key) { if (root == NULL) { // 空位:建新节点 Node *n = malloc(sizeof(Node)); n->val = key; n->left = n->right = NULL; return n; } if (key < root->val) root->left = insert(root->left, key); else root->right = insert(root->right, key); return root; }

注意:BST 按顺序插入会退化成链表(1,2,3,4 串成一条),查找就变成 O(n)。工程上用平衡树(AVL、红黑树)防止它退化成链——Linux 内核、C++ map 都是红黑树。理解 BST 就理解了后面一切平衡树的基础。

配套:有序数组上的二分查找(BST 思想的数组版)

// 在升序数组 a[0..n-1] 里找 key,找到返回下标,否则 -1 int bsearch(int a[], int n, int key) { int lo = 0, hi = n - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; // 防 (lo+hi) 溢出 if (a[mid] == key) return mid; else if (a[mid] < key) lo = mid + 1; // 去右半 else hi = mid - 1; // 去左半 } return -1; }