搞定线性表添加一个元素代码,C语言实现细节剖析

讲真,我第一次看数据结构,看到线性表添加一个元素代码那块儿,头都大了。一堆指针,一堆循环,i 和 j 飞来飞去,感觉脑子里的内存都快溢出了。但后来真的静下心来,把那段代码掰开揉碎了看,才发现,嗨,不就是那么回事儿嘛。

这事儿,你得先有个画面感。

别想什么数组、内存地址,那些太抽象。你就想,你在排一队人。一队人整整齐齐站着,这就是一个顺序存储的线性表。现在,你想在队伍中间的某个位置,比如说第 i 个位置,插进来一个人。怎么办?

你总不能直接把新人往第 i 个人身上一堆吧?那不就叠罗汉了。

正确操作是啥?你得对着排在第 i 个位置以及他后面的所有人喊:“嘿,哥儿们,麻烦都往后挪一个位置!”

于是,队伍最后那个人,先往后退一步,给他前面的人腾出个空位。然后他前面那个人,再退一步,占据刚才那个空位…这个过程就像多米诺骨牌,从队尾开始,一个一个地往后传,直到传到你想要插入的那个位置,也就是第 i 个位置。现在,第 i 个位置是不是就空出来了?好了,让新人站进去。最后,别忘了告诉计数的管理员,现在队伍里多了一个人。

整个过程,就三步:
1. 让第 i 个位置后面的人元素后移
2. 把新人安顿在空出来的第 i 个位置。
3. 更新整个队伍的总人数。

把这个场景翻译成代码,尤其是C语言,就成了我们看到的那个经典模样。咱们就拿最常见的顺序表(也就是数组实现)来说事儿。

假设我们有这么个结构体:

“`c

define MAXSIZE 100 // 假设最大容量是100

typedef struct {
int data[MAXSIZE]; // 用数组存数据
int length; // 当前线性表的长度
} SqList;
“`

现在,我们要写一个函数 ListInsert(SqList *L, int i, int e),意思是在线性表 L 的第 i 个位置,插入元素 e。

“`c
// 在顺序线性表L的第i个位置之前插入新的元素e
// i的合法值为1 <= i <= L.length + 1
bool ListInsert(SqList *L, int i, int e) {
// 首先,你得检查一下,别让人瞎搞。
// 队伍满了没?插队的位置对不对?
if (L->length == MAXSIZE) { // 线性表已满,插不进来了
return false;
}
if (i < 1 || i > L->length + 1) { // i值不合法
return false;
}

// 关键时刻来了!开始挪动元素了。
// 注意,是从队尾开始挪!
if (i <= L->length) { // 只有当插入位置不在表尾时,才需要移动元素
    for (int j = L->length - 1; j >= i - 1; j--) {
        L->data[j + 1] = L->data[j]; // 元素后移
    }
}

// 好了,位置腾出来了,把新人放进去。
L->data[i - 1] = e; // 数组下标是从0开始的,所以是i-1

// 最后,别忘了更新长度!
L->length++;

return true;

}
“`

这段代码,就是那个排队场景的完美复刻。

我们来细品一下那个 for 循环,这可是灵魂所在。for (int j = L->length - 1; j >= i - 1; j--)

为什么 j 的初始值是 L->length - 1?因为这是当前队伍里最后一个人的数组下标啊!我们得从他开始挪。

为什么是 j-- 递减循环?废话,肯定是倒着挪才行啊!你要是从前往后挪,L->data[j] 的值直接被 L->data[j-1] 覆盖了,那后面的人还挪个啥?原始数据早就没了,你只会得到一串重复的数据。这个坑,我当年可是实实在在踩进去过,debug了半天,才发现自己傻得可爱。

为什么循环的条件是 j >= i - 1?因为我们要挪动的,是所有从第 i 个位置(数组下标 i-1)开始的人。当 j 等于 i-1 的时候,就是把原来第 i 个位置的人挪到了第 i+1 个位置,正好把第 i 个位置腾出来。完美。

这就是线性表添加一个元素代码的精髓:边界检查元素后移插入赋值长度更新

当然,这是顺序表。它最大的优点是读取快,但插入和删除就麻烦了,因为要“牵一发而动全身”,挪动一大片元素。

要是换成链表,那故事就完全不一样了。

链表就像一群手拉手的小朋友,每个人只知道自己前面和后面的人是谁。你想在中间插一个人进来?太简单了。

找到要插入位置前面的那个小朋友A,和位置上的小朋友B。
你让新人伸出左手,拉住A的右手。
然后让新人伸出右手,拉住B的左手。
最后,你让A松开原来拉着B的手。
搞定!

整个过程,根本不需要其他小朋友动地方,只需要改变几只“手”的拉手对象就行了。这在代码里,就是修改几个指针的事儿。效率高得不知道哪里去了。

所以你看,同样是实现“添加一个元素”,不同的存储结构,背后的逻辑和代码实现,简直是天差地别。理解了那个排队的场景,顺序表的插入代码就再也难不倒你了。它不再是一堆冰冷的符号,而是一个鲜活、有序的挪动过程。把这个想透了,数据结构才算真正入了门。


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注