掌握数据结构基本操作,让代码更高效

写程序时你有没有遇到过这种情况:明明逻辑没问题,可一到处理大量数据就卡得不行?比如做个通讯录,查个人要等好几秒,删个联系人还得转半天。问题可能不在思路,而在“怎么存数据”上。

什么是数据结构基本操作

数据结构说白了就是数据的存放方式。不同的结构,支持的操作效率也不同。常见的基本操作有增、删、查、改,但具体怎么实现,差别可大了。

比如数组和链表都能存一组数,但它们的操作特点完全不同。

数组:连续存储,查得快,插得慢

数组像是一排整齐的格子,每个位置都有编号(下标)。你想查第5个元素,直接去5号格子拿就行,时间几乎不花,这就是O(1)的查询效率。

但如果你想在中间插入一个新元素,比如在第3个位置插一个数,那第3个以后的所有数据都得往后挪一位。数据越多,挪得越久,这就是O(n)的时间开销。

int arr[5] = {10, 20, 30, 40, 50};
// 想在索引2位置插入25
// 需要把30、40、50都往后移,再把25放进去

链表:灵活连接,插得快,查得慢

链表像是用绳子串起来的一串钥匙环,每个环里存数据和下一个环的地址。你不能直接跳到第5个,只能从第一个开始一个个找,所以查一个元素可能是O(n)

但插入就轻松多了。只要找到位置,断开绳子,把新环接进去就行,前后两个环重新连一下,其他数据完全不用动。

struct Node {
    int data;
    struct Node* next;
};

// 插入新节点
Node* newNode = new Node();
newNode->data = 25;
newNode->next = current->next;
current->next = newNode;

栈和队列:特殊规则下的高效操作

栈像是一摞盘子,只能从上面拿或放,遵循“后进先出”(LIFO)。这种限制反而让它在函数调用、撤销操作(比如Ctrl+Z)中特别有用。

队列则像排队买奶茶,先来的先服务,叫“先进先出”(FIFO)。消息系统、任务调度都靠它。

它们的基本操作——入栈/出栈、入队/出队——都是O(1),因为只在固定端进行。

树:分层管理,快速查找

如果你用过文件夹,那你已经用过树结构了。根目录是根节点,下面分出子文件夹,层层嵌套。

二叉搜索树更聪明,左边的小,右边的大。查一个数时,每次比较都能排除一半,效率达到O(log n),比一个个找快多了。

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

实际场景中的选择

做购物车功能,频繁添加删除商品,用链表比数组更合适;做排行榜,需要快速按分数排序访问,用堆(一种特殊的树)更高效;做字典查询,键值匹配,哈希表几乎是首选。

每种结构都有它的“舒适区”。了解基本操作的特点,才能在写代码时不光让程序跑起来,还能让它跑得快、扛得住压力。