本文主要是介绍无头结点单向非循环链表的基本操作(c语言实现),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
结点
在C语言中,单链表的结点通常是一个结构体,它包含一个数据域用于存储数据,以及一个指针域用于指向链表中的下一个结点。
下面是一个简单的单链表结点的定义:
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;
在这段代码中,首先定义了一个新的数据类型别名 SLTDataType
,它实际上就是 int
类型。这样做的好处是,如果将来需要改变链表中存储的数据类型,只需要修改 SLTDataType
的定义即可,而不需要修改链表中所有使用这种数据类型的地方。
接着定义了一个结构体 SListNode
,这个结构体代表单链表中的一个结点。
结构体中包含两个成员:
data
:类型为SLTDataType
(也就是int
),用于存储该结点的数据。next
:类型为指向SListNode
类型的指针,用于指向链表中的下一个结点。
最后,为这个结构体类型定义了一个别名 SLTNode
。在后续的代码中,可以使用 SLTNode
来代替 struct SListNode
,使得代码更加简洁。
这样定义单链表的结点之后,就可以方便地创建和操作链表了。
头指针
头指针是一个指针,它指向链表或链表中的第一个节点。
在链表中,每个节点包含一个数据项和一个指向下一个节点的指针。
通过头指针,我们可以访问链表中的第一个节点,然后可以通过节点的指针访问下一个节点,以此类推。使用头指针,我们可以对链表进行插入、删除、查找等操作。
头指针在确定线性表中第一个元素对应的存储位置时非常有用,它一般用于处理数组、链表、队列等数据结构。在链式存储中,只要不是循环链表,就一定存在头指针。单链表可以用头指针的名字来命名,头指针指向第一个节点
链表的基本操作
一,创建新结点
SLTNode* BuySLTNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}
这段代码定义了一个名为 BuySLTNode
的函数,用于创建一个新的单链表节点,并将新节点的数据部分初始化为传入的参数 x
,同时将其 next
指针初始化为 NULL
。
首先,函数通过调用 malloc
函数为新的 SLTNode
分配内存空间。sizeof(SLTNode)
用于计算 SLTNode
类型所需的内存大小,确保分配足够的空间来存储新节点。
接下来,函数检查 malloc
是否成功分配了内存。如果 malloc
返回 NULL
,表示内存分配失败(可能是由于内存不足),函数会调用 perror
函数输出错误信息 "malloc fail",并返回 NULL
,表示创建新节点失败。
如果内存分配成功,函数将新节点的 data
字段设置为传入的参数 x
,即节点所要存储的数据。同时,将新节点的 next
指针初始化为 NULL
,表示该节点当前是链表的最后一个节点,没有指向下一个节点的指针。
最后,函数返回新创建的节点的指针,供调用者使用。调用者可以通过这个指针访问和操作新创建的节点。
二,尾部插入一个元素
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);if (*pphead == NULL){*pphead = newnode;}else{// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}
这段代码定义了一个函数 SLTPushBack,用于在单链表的尾部添加一个新的节点。函数接收两个参数:一个指向头节点指针的指针 pphead 和一个要添加到链表中的数据类型 x。
下面是该函数的详细解释:
断言检查:
assert(pphead);
使用 assert 来确保 pphead 不为 NULL。
如果 pphead 是 NULL,程序会在调试模式下终止,并输出错误信息。这是为了防止对空指针进行解引用,从而导致程序崩溃。
创建新节点:
SLTNode* newnode = BuySLTNode(x);
调用之前定义的 BuySLTNode 函数来创建一个新的节点,并将数据 x 赋给这个新节点的 data 字段。BuySLTNode 会负责分配内存并返回新节点的指针。
处理链表为空的情况:
if (*pphead == NULL) { *pphead = newnode; }
如果链表为空(即头节点指针 *pphead 为 NULL),则直接将新节点设置为头节点。
找到链表尾部并添加新节点:
else { // 找尾 SLTNode* tail = *pphead; while (tail->next != NULL) { tail = tail->next; } tail->next = newnode; }
如果链表不为空,则需要遍历链表找到尾部的节点。
使用 tail 指针从头节点开始,沿着 next 指针逐步向后移动,直到找到 next 指针为 NULL 的节点,即尾节点。
然后,将尾节点的 next 指针指向新创建的节点 newnode,从而将新节点添加到链表的尾部。
错误处理:
如果 BuySLTNode 函数因为内存分配失败而返回 NULL,SLTPushBack 函数并没有包含直接处理这种情况的代码。在实际应用中,你可能希望在 BuySLTNode 返回 NULL 时进行错误处理,比如打印错误信息或者返回一个错误码。
这个函数实现了在单链表尾部添加节点的功能,无论链表是空的还是有元素的,都能正确工作。
需要注意的是,它假设 pphead 指向的是头节点的指针,而不是头节点本身。
这意味着,如果链表为空,*pphead 将会被设置为新节点的地址;如果链表非空,则不会改变头节点的地址,只是链表的长度会增加。
三,头部插入一个元素
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);newnode->next = *pphead;*pphead = newnode;
}
这段代码定义了一个函数 SLTPushFront,用于在单链表的头部插入一个新的节点。函数接收两个参数:一个指向头节点指针的指针 pphead 和一个要插入到链表中的数据类型 x。
下面是该函数的详细解释:
断言检查:
assert(pphead);
使用 assert 来确保 pphead 不为 NULL。这确保了传递给函数的参数是有效的,防止了因为无效的指针而导致的潜在问题。
创建新节点:
SLTNode* newnode = BuySLTNode(x);
调用之前定义的 BuySLTNode 函数来创建一个新的节点,并将数据 x 赋给这个新节点的 data 字段。
更新新节点的 next 指针:
newnode->next = *pphead;
将新节点的 next 指针指向当前的头节点。这实际上是将新节点插入到链表的开始位置,因为新节点现在指向了原来链表的第一个节点(如果有的话)。
更新头节点指针:
*pphead = newnode;
将头节点指针 *pphead 更新为新节点的地址。这意味着现在新节点成为了链表的头节点,而原来的头节点(如果有的话)则成为了新节点的下一个节点。
这个函数实现了在单链表头部插入节点的功能。无论链表是空的还是有元素的,都能正确工作。在链表为空的情况下,新节点将成为唯一的节点,并且头节点指针 *pphead 将指向这个新节点。在链表非空的情况下,新节点将被插入到原来头节点的前面,成为新的头节点。
需要注意的是,SLTPushFront 函数假设 pphead 指向的是头节点的指针的地址,因此它可以直接修改头节点指针的值。如果 pphead 指向的是头节点本身而不是其地址,那么函数将无法修改链表的头节点,因为传递的是头节点值的一个副本。在这个实现中,通过传递指针的指针,我们确保了可以修改头节点指针本身。
四,删除最后一个结点
void SLTPopBack(SLTNode** pphead)
{assert(pphead);assert(*pphead);// 1、只有一个节点// 2、多个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
}
这段代码定义了一个函数 SLTPopBack,用于删除单链表的尾部节点,并释放其占用的内存。函数接收一个指向头节点指针的指针 pphead 作为参数。
下面是该函数的详细解释:
断言检查:
assert(pphead); assert(*pphead);
使用 assert 来确保 pphead 和 *pphead 都不为 NULL。这确保了传递给函数的参数是有效的,并且链表至少有一个节点。
处理只有一个节点的情况:
if ((*pphead)->next == NULL) { free(*pphead); *pphead = NULL; }
如果链表中只有一个节点(即头节点的 next 指针为 NULL),则直接释放这个节点的内存,并将头节点指针 *pphead 设置为 NULL,表示链表现在为空。
处理有多个节点的情况:
else { SLTNode* tail = *pphead; while (tail->next->next != NULL) { tail = tail->next; } free(tail->next); tail->next = NULL; }
如果链表中有多个节点,我们需要找到尾节点的前一个节点(我们称之为 tail),然后释放尾节点的内存,并将 tail 节点的 next 指针设置为 NULL,以断开链表连接。
在循环中,tail 指针逐步移动到尾节点的前一个位置。循环的条件是 tail->next->next != NULL,这意味着 tail 指针当前指向的节点的下一个节点(tail->next)不是尾节点,因为尾节点的 next 指针为 NULL。当循环结束时,tail 指向的就是尾节点的前一个节点。
然后,使用 free(tail->next) 释放尾节点的内存,并将 tail->next 设置为 NULL,完成尾节点的删除操作。
需要注意的是,这个 SLTPopBack 函数假设链表至少有一个节点。如果链表为空(即 *pphead 为 NULL),则函数的行为是未定义的,因为会尝试解引用一个空指针。在实际应用中,你可能希望在函数开始处添加一个检查,以确保链表不为空,或者至少确保 pphead 不为 NULL。此外,如果链表只有一个节点,该函数也能正确工作,因为第一个 if 语句会处理这种情况。
另外,这个函数的实现方式假设了链表至少有两个节点才调用 SLTPopBack。如果链表只有一个节点,应该由调用者确保不会调用这个函数,或者应该在函数内部进行更严格的检查以避免潜在的错误。
五,删除第一个元素
void SLTPopFront(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* first = *pphead;*pphead = first->next;free(first);first = NULL;
}
这段代码定义了一个函数 SLTPopFront,用于删除单链表的头部节点,并释放其占用的内存。函数接收一个指向头节点指针的指针 pphead 作为参数。
下面是该函数的详细解释:
断言检查:
assert(pphead); assert(*pphead);
使用 assert 来确保 pphead 和 *pphead 都不为 NULL。这确保了传递给函数的参数是有效的,并且链表至少有一个节点。
删除头部节点:
SLTNode* first = *pphead;
将头节点指针 *pphead 的值赋给一个新的指针变量 first。现在 first 指向链表原来的头节点。
更新头节点指针:
*pphead = first->next;
将头节点指针 *pphead 更新为原来头节点的下一个节点,这样原来的头节点就不再是链表的头节点了。
释放头部节点的内存:
free(first);
释放 first 指针指向的头节点的内存。由于 first 现在不再被链表使用,它的内存可以被操作系统回收。
重置 first 指针:
first = NULL;
将 first 指针设置为 NULL,以避免悬挂指针。这是一个好的编程习惯,因为它可以防止后续的代码错误地访问已经被释放的内存。
这个函数实现了在单链表头部删除节点的功能。无论链表是只有一个节点还是有多个节点,它都能正确工作。在删除头部节点后,链表的头节点将变为原来的第二个节点(如果存在的话),或者链表将变为空(如果原来只有一个节点)。
需要注意的是,这个函数假设链表至少有一个节点。如果链表为(即 *pphead 为 NULL),则函数行为是未定义的,因为会尝试解引用一个空指针。
在实际应用中,你应该在调用 SLTPopFront 之前确保链表不为空,或者在函数内部添加额外的检查来处理空链表的情况。
六,查找特定值的结点
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}
这段代码定义了一个函数 SLTFind,用于在单链表中查找一个具有特定数据值的节点。函数接收两个参数:一个指向链表头节点的指针 phead 和一个要查找的数据值 x。
下面是该函数的详细解释:
初始化当前节点指针:
SLTNode* cur = phead;
将 cur 指针初始化为链表的头节点 phead。这个指针将用于遍历链表。
遍历链表:
while (cur)
使用一个 while 循环遍历链表,直到 cur 指针为 NULL(即链表结束)。
查找节点:
if (cur->data == x) { return cur; }
在循环内部,检查当前节点 cur 的数据值是否等于要查找的数据值 x。如果相等,说明找到了匹配的节点,函数返回该节点的地址。
移动到下一个节点:
cur = cur->next;
如果当前节点的数据值不等于 x,则将 cur 指针移动到下一个节点,继续查找。
返回 NULL:
return NULL;
如果循环结束时仍然没有找到匹配的节点(即 cur 为 NULL),则函数返回 NULL,表示未找到。
这个函数通过遍历链表来查找具有特定数据值的节点。
如果找到匹配的节点,则返回该节点的地址;否则返回 NULL。
这个查找过程的时间复杂度是 O(n),其中 n 是链表的长度,因为在最坏的情况下,可能需要遍历整个链表。
七,在pos位置前插入一个元素
// pos之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pos);assert(pphead);if (pos == *pphead){SLTPushFront(pphead, x);}else{// 找到pos的前一个位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuySLTNode(x);prev->next = newnode;newnode->next = pos;}
}
这段代码定义了一个函数 SLTInsert,用于在单链表的指定位置 pos 之前插入一个新的节点,新节点的数据值为 x。
函数接收三个参数:一个指向头节点指针的指针 pphead,一个指向链表中某个节点的指针 pos,以及要插入的新节点的数据值 x。
下面是该函数的详细解释:
断言检查:
assert(pos); assert(pphead);
使用 assert 来确保 pos 和 pphead 都不为 NULL。这确保了传递给函数的参数是有效的。
检查插入位置:
if (pos == *pphead) { SLTPushFront(pphead, x); }
如果 pos 指向的节点是头节点,那么实际上我们需要在链表头部插入新节点。这里调用了 SLTPushFront 函数来完成这一操作。
找到 pos 的前一个节点:
SLTNode* prev = *pphead; while (prev->next != pos) { prev = prev->next; }
如果 pos 不是头节点,那么我们需要找到 pos 的前一个节点 prev。这个循环从头节点开始,逐个遍历节点,直到找到 prev 节点的 next 指针指向 pos。
创建新节点并插入:
SLTNode* newnode = BuySLTNode(x); prev->next = newnode; newnode->next = pos;
使用 BuySLTNode 函数(这个函数在代码片段中没有给出,但我们可以假设它用于创建并初始化一个新节点)来创建一个包含数据值 x 的新节点 newnode。
然后,更新 prev 节点的 next 指针,使其指向新节点 newnode,并将 newnode 的 next 指针指向原来的 pos 节点。
这样,新节点就被插入到了 pos 节点之前。
这个函数实现了在单链表指定位置插入新节点的功能。它首先检查插入位置是否为链表头部,如果是,则调用专门的头部插入函数。如果不是头部,则找到插入位置的前一个节点,并在该位置插入新节点。
需要注意的是,这个函数假设 pos 指向的节点确实存在于链表中,并且 pos 不是 NULL。如果 pos 不指向链表中的有效节点,则函数的行为是未定义的。
在实际应用中,你应该在调用 SLTInsert 之前确保 pos 指向的节点是链表中的一个有效节点。
八,删除pos位置的元素
// pos位置删除
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);//assert(*pphead);if (*pphead == pos){SLTPopFront(pphead);}else{// 找到pos的前一个位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);//pos = NULL;}
}
这段代码定义了一个函数 SLTErase,用于在单链表中删除指定位置的节点 pos。
函数接收两个参数:一个指向头节点指针的指针 pphead 和一个指向要删除节点的指针 pos。
下面是该函数的详细解释:
断言检查:
assert(pphead); assert(pos);
使用 assert 来确保 pphead 和 pos 都不为 NULL。这确保了传递给函数的参数是有效的。
检查删除位置:
if (*pphead == pos) { SLTPopFront(pphead); }
如果 pos 指向的节点是头节点,那么实际上我们需要删除链表头部节点。这里调用了 SLTPopFront 函数来完成这一操作。
找到 pos 的前一个节点:
SLTNode* prev = *pphead; while (prev->next != pos) { prev = prev->next; }
如果 pos 不是头节点,那么我们需要找到 pos 的前一个节点 prev。这个循环从头节点开始,逐个遍历节点,直到找到 prev 节点的 next 指针指向 pos。
删除节点:
prev->next = pos->next; free(pos);
更新 prev 节点的 next 指针,使其跳过 pos 节点,直接指向 pos 的下一个节点。这样,pos 节点就被从链表中移除了。接着,调用 free 函数释放 pos 节点占用的内存。
注释掉的代码:
pos = NULL;
这行代码被注释掉了,通常这样的代码用于将 pos 指针设置为 NULL,以避免悬挂指针。但在这种情况下,由于 pos 是作为参数传递进来的,将 pos 设置为 NULL 并不会影响到调用者处的 pos 指针。因此,这行代码在这里是没有必要的,也不会影响到函数的正确性。
这个函数实现了在单链表中删除指定位置节点的功能。它首先检查要删除的节点是否为链表头部,如果是,则调用专门的头部删除函数。如果不是头部,则找到要删除节点的前一个节点,并更新其 next 指针来跳过要删除的节点。最后,释放要删除节点的内存。
需要注意的是,这个函数假设 pos 指向的节点确实存在于链表中,并且 pos 不是 NULL。如果 pos 不指向链表中的有效节点,则函数的行为是未定义的。
在实际应用中,你应该在调用 SLTErase 之前确保 pos 指向的节点是链表中的一个有效节点。
九,在pos位置后插入一个元素
// pos后面插入
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);newnode->next = pos->next;pos->next = newnode;
}
这段代码定义了一个函数 SLTInsertAfter,用于在单链表中指定节点 pos 的后面插入一个新的节点,新节点的数据值为 x。函数接收两个参数:一个指向链表中某个节点的指针 pos 和要插入的新节点的数据值 x。
下面是该函数的详细解释:
断言检查:
assert(pos);
使用 assert 来确保 pos 不为 NULL。这确保了传递给函数的参数是有效的。
创建新节点:
SLTNode* newnode = BuySLTNode(x);
使用 BuySLTNode 函数(这个函数在代码片段中没有给出,但我们可以假设它用于创建并初始化一个新节点)来创建一个包含数据值 x 的新节点 newnode。
插入新节点:
newnode->next = pos->next; pos->next = newnode;
首先,将新节点 newnode 的 next 指针设置为 pos 节点的 next 指针所指向的节点。这样,新节点就指向了原来 pos 节点后面的节点。然后,将 pos 节点的 next 指针更新为指向新节点 newnode。这样,新节点就被插入到了 pos 节点的后面。
这个函数实现了在单链表中指定节点后面插入新节点的功能。它假设 pos 指向的节点确实存在于链表中,并且 pos 不是 NULL。如果 pos 不指向链表中的有效节点,则函数的行为是未定义的。在实际应用中,你应该在调用 SLTInsertAfter 之前确保 pos 指向的节点是链表中的一个有效节点。
这个函数没有处理头节点插入的特殊情况,因为从函数参数和逻辑上看,它假设 pos 是链表中的一个非头节点。如果需要处理头节点插入的情况,你需要修改函数逻辑或者在调用这个函数之前先检查 pos 是否为头节点,并相应地处理。
十,在pos位置后面删除一个元素
// pos位置后面删除
void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
这段代码定义了一个函数 SLTEraseAfter,用于在单链表中删除指定节点 pos 后面的节点。函数接收一个参数:一个指向链表中某个节点的指针 pos。
下面是该函数的详细解释:
断言检查:
assert(pos); assert(pos->next);
使用 assert 来确保 pos 不为 NULL,并且 pos 指向的节点后面确实有另一个节点(即 pos->next 不为 NULL)。这确保了传递给函数的参数是有效的,并且不会在尝试访问 pos->next 时导致空指针解引用错误。
删除节点:
SLTNode* del = pos->next; pos->next = del->next; free(del); del = NULL;
首先,将 pos 节点后面的节点(即 pos->next)的指针赋值给 del。然后,更新 pos 节点的 next 指针,使其跳过 del 节点,直接指向 del 节点的下一个节点。
这样,del 节点就被从链表中移除了。接着,调用 free 函数释放 del 节点占用的内存。
需要注意的是,虽然 del = NULL; 这行代码在函数内部将 del 设置为 NULL,但这并不会影响到函数外部的任何指针。
因为 del 只是一个局部变量,它的改变不会影响到函数外部的变量。这行代码主要是为了在函数内部避免使用已经被释放的 del 指针,从而防止潜在的错误。
这个函数实现了在单链表中删除指定节点后面节点的功能。它假设 pos 指向的节点确实存在于链表中,并且 pos 后面确实有另一个节点。如果 pos 不指向链表中的有效节点,或者 pos 是链表的最后一个节点,则函数的行为是未定义的。在实际应用中,你应该在调用 SLTEraseAfter 之前确保 pos 指向的节点是链表中的一个有效节点,并且它不是链表的最后一个节点。
十一,打印链表
void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;//while (cur->next != NULL)//while(cur != NULL)while (cur){printf("%d->", cur->data);cur = cur->next;//cur++;}printf("NULL\n");
}
完整操作
void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;//while (cur->next != NULL)//while(cur != NULL)while (cur){printf("%d->", cur->data);cur = cur->next;//cur++;}printf("NULL\n");
}SLTNode* BuySLTNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);if (*pphead == NULL){*pphead = newnode;}else{// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);newnode->next = *pphead;*pphead = newnode;
}void SLTPopBack(SLTNode** pphead)
{// 暴力检查assert(pphead);assert(*pphead);// 温柔的检查//if (*pphead == NULL)// return;// 1、只有一个节点// 2、多个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{// 找尾//SLTNode* prev = NULL;//SLTNode* tail = *pphead;//while (tail->next != NULL)//{// prev = tail;// tail = tail->next;//}//free(tail);//tail = NULL;//prev->next = NULL;SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
}void SLTPopFront(SLTNode** pphead)
{// 暴力检查assert(pphead);assert(*pphead);// 温柔的检查//if (*pphead == NULL)// return;SLTNode* first = *pphead;*pphead = first->next;free(first);first = NULL;
}SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}// pos之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pos);assert(pphead);if (pos == *pphead){SLTPushFront(pphead, x);}else{// 找到pos的前一个位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuySLTNode(x);prev->next = newnode;newnode->next = pos;}
}// pos位置删除
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);//assert(*pphead);if (*pphead == pos){SLTPopFront(pphead);}else{// 找到pos的前一个位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);//pos = NULL;}
}// pos后面插入
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);newnode->next = pos->next;pos->next = newnode;
}// pos位置后面删除
void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);//SLTNode* del = pos->next;//pos->next = pos->next->next;//free(del);//del = NULL;SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
这篇关于无头结点单向非循环链表的基本操作(c语言实现)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!