错误代码3:
画图:
void SLPushFront(SLTNode** pphead, SLTDataType x);
void SLPushBack(SLTNode* phead, SLTDataType x);
void TestSList2()
{
SLTNode* plist = NULL;
SLPushBack(plist, 1);
SLPushBack(plist, 2);
SLTPrint(plist);
}
void SLPushBack(SLTNode* phead, SLTDataType x)
{
SLTNode* newnode = BuyLTNode(x);
if (phead == NULL)
{
phead = newnode;
}
else
{
SLTNode* tail = phead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
输出:
列举了这么多错误案例接下来到正确案例:
void SLPushBack(SLTNode** pphead, SLTDataType x) void TestSList2() { SLTNode* plist = NULL; SLPushBack(&plist, 1); SLPushBack(&plist, 2); SLPushBack(&plist, 3); SLPushBack(&plist, 4); SLTPrint(plist); } //要让新节点和tail链接起来,一定要去改tail的next void SLPushBack(SLTNode** pphead, SLTDataType x)//尾插的本质是让上一个结点链接下一个结点 { SLTNode* newnode = BuyLTNode(x); // 1、空链表 // 2、非空链表 if (*pphead == NULL) { *pphead = newnode; } else { SLTNode* tail = *pphead; while (tail->next != NULL) { tail = tail->next; } tail->next = newnode; } }
代码执行:
2.5单链表头插
头插思路:
头插第二个节点思路:
头插的代码可以写成这样
void SLPushFront(SLTNode** pphead, SLTDataType x) { SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//使用malloc函数动态分配了一个大小为SLTNode的内存块, //并将其强制转换为 SLTNode 指针类型,即创建了一个新的节点。 if (newnode == NULL) { perror("malloc fail"); return NULL; } //需要注意的是,在使用 malloc 函数动态分配内存时,需要手动释放内存,否则会导致内存泄漏 //因此,在创建单链表节点后,我们应该在适当的时候使用 free 函数释放节点所占用的内存 newnode->data = x; newnode->next = NULL; //return newnode;//返回的是一个结点的地址 newnode->next = *pphead; *pphead = newnode;//将头节点*pphead 更新为新节点的地址,以使新节点成为新的头节点。 }
但是为了避免创建新节点的程序重复编写,可以利用上面的BuyLTNode(x)函数定义新节点达成简写的目的,也可以头插的函数也可以写成这样:
void SLPushFront(SLTNode** pphead, SLTDataType x) { SLTNode* newnode = BuyLTNode(x); newnode->next = *pphead; *pphead = newnode; }
在
SLPushFront
函数中,我们首先调用BuyLTNode(x)
函数创建一个新的节点,然后将新节点的next
指针指向当前链表头节点,接着将链表头指针指向新节点,从而完成了在链表头部插入新节点的操作。
代码执行:
2.6单链表尾删
错误案例:
方法1:
方法2:
代码实例:
void SLPopBack(SLTNode** pphead) { //没有节点(空链表) //暴力检查 assert(*pphead); //温柔检查 if (*pphead == NULL) { return; } //一个节点 if ((*pphead)->next == NULL) { free(*pphead); *pphead = NULL; }//多个节点 else { SLTNode* prev = NULL; SLTNode* tail = *pphead; //找尾 //方法一 /*while (tail->next) { prev = tail; tail = tail->next; } free(tail); prev->next = NULL;*/ //方法二 SLTNode* tail = *pphead; while (tail->next->next) { tail = tail->next; } free(tail->next); tail->next = NULL; } }
执行:
2.7单链表头删
思路:
void SPopFront(SLTNode** pphead) { //没有节点 //暴力检查 assert(*pphead); //温柔检查 if (*pphead == NULL) return;// 一个节点 if ((*pphead)->next == NULL) { free(*pphead); *pphead = NULL; } //多个节点 else { SLTNode* del = *pphead;//相当于一个标记,删掉的标记 //写法一 //*pphead = del->next; //写法二 *pphead = (*pphead)->next; free(del); } }
执行:
2.8单链表查找/修改某个值
使用尾插将1,2,3,4按先后顺序分别插入链表中,接着找到链表中值为3的元素,并把其改为30(可以通过定义结构体类型的指针访问data为3的结点,并直接通过pos->next=30修改)
注意:直接在main函数内定义一个test函数修改值即可,不必另定义新函数。
SLTNode* STFind(SLTNode* phead, SLTDataType x) { //assert(phead); SLTNode* cur = phead; while (cur) { if (cur->data == x) { return cur; } cur = cur->next; } return NULL; }
执行: