一、链表概念
1、线性表是一种常用的简单数据结构,它是由零个或多个元素组成的有限序列。强调了元素的有限性和元素之间的顺序性。
线性表有两种物理结构,第一种是顺序存储结构,例如我们熟悉的数组。
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
顺序结构最大的特点就是:顺序存储,随机访问 。对于初学者来说使用非常便利。但是,它致命的缺点在于:
2、相邻的两元素的存储位置(地址)也具有邻居关系,导致进行插入、删除等操作时需要移动大量元素,耗费时间。
3、使用前需声明数组的长度,开辟固定的空间,且后续不能再修改。
4、只能存储一种类型的数据,内容单一,无法满足实际应用。
于是我们引入了线性表的另一种物理结构:链式存储结构。
链式存储结构的特点是用一组任意的存储单元来存储线性表的数据元素,不要求它们的地址相连,需要的时候就开辟新的空间。
二、链表和数组的区别和分别用不同的方法实现
#include <stdio.h>
struct Test
{
int data; // 数据:存储整数值
struct Test *next; // 指针头节点:指向下一个结构体的指针
};
void printLink(struct Test *head)
{
struct Test *ponint = head; // 初始化ponint指针,指向链表的头节点
while (ponint != NULL) // 循环直到ponint为NULL,表示链表结束
{
printf("%d ", ponint->data); // 打印当前节点的数据
ponint = ponint->next; // 将ponint更新为指向下一个节点
}
putchar('\n'); // 打印换行符
}
int main()
{
int i;
int arr[] = {1, 2, 3}; // 定义并初始化一个整数数组
int arr_size = sizeof(arr) / sizeof(arr[0]); // 计算数组的元素个数
for (i = 0; i < arr_size; i++) // 遍历数组中的每个元素
{
printf("arr: %d ", arr[i]); // 打印数组中的每个元素
}
printf("\n=================\n"); // 打印分隔线
struct Test t1 = {1, NULL}; // 定义并初始化链表的第一个节点
struct Test t2 = {2, NULL}; // 定义并初始化链表的第二个节点
struct Test t3 = {3, NULL}; // 定义并初始化链表的第三个节点
struct Test t4 = {4, NULL}; // 定义并初始化链表的第四个节点
struct Test t5 = {5, NULL}; // 定义并初始化链表的第五个节点
struct Test t6 = {6, NULL}; // 定义并初始化链表的第六个节点
t1.next = &t2; // 设置t1的next指针,指向t2
t2.next = &t3; // 设置t2的next指针,指向t3
t3.next = &t4; // 设置t3的next指针,指向t4
t4.next = &t5; // 设置t4的next指针,指向t5
t5.next = &t6; // 设置t5的next指针,指向t6
printf("t1到t6的值是:");
printLink(&t1); // 调用printLink函数,从t1开始打印整个链表的数据
return 0;
}
这段代码是一个简单的例子,展示了结构体、数组和链表的使用。 代码的详细解释如下: 1. 头文件`<stdio.h>`用于包含标准输入输出库。 2. 定义了一个结构体`Test`,它包含一个整型成员`data`和一个指向结构体自身的指针成员`next`。 3. 在`main`函数中,声明并初始化了一个整型数组`arry`,其中存储了三个整数。 4. 使用`for`循环遍历数组`arry`,并使用`printf`语句打印出每个数组元素。 5. 声明并初始化了三个结构体变量`t1`、`t2`和`t3`,分别存储了整数数据和指针。 6. 通过指针的方式,将这三个结构体变量构建成链表。具体地,将`t1`的`next`成员指向`t2`,将`t2`的`next`成员指向`t3`。 7. 使用`printf`语句打印出链表中的数据。首先输出了使用`t1`的`data`成员,然后使用`t1.next->data`和`t1.next->next->data`依次访问链表中的数据。 8. 最后,返回值`0`表示程序成功执行结束。 代码的运行结果如下: 1 2 3 use t1 to print three nums 1 2 3 在循环部分,数组中的元素依次被打印输出。 在链表部分,通过`t1`的`data`成员和指向下一个节点的指针,可以依次访问并打印出链表中的三个数字。
三、静态链表添加动态遍历
#include <stdio.h>
struct Test
{
int data; // 数据:存储整数值
struct Test *next; // 指针头节点:指向下一个结构体的指针
};
void printLink(struct Test *head)
{
struct Test *ponint = head; // 初始化ponint指针,指向链表的头节点
while (ponint != NULL) // 循环直到ponint为NULL,表示链表结束
{
printf("%d ", ponint->data); // 打印当前节点的数据
ponint = ponint->next; // 将ponint更新为指向下一个节点
}
putchar('\n'); // 打印换行符
}
int main()
{
int i;
int arr[] = {1, 2, 3}; // 定义并初始化一个整数数组
int arr_size = sizeof(arr) / sizeof(arr[0]); // 计算数组的元素个数
for (i = 0; i < arr_size; i++) // 遍历数组中的每个元素
{
printf("arr: %d ", arr[i]); // 打印数组中的每个元素
}
printf("\n=================\n"); // 打印分隔线
struct Test t1 = {1, NULL}; // 定义并初始化链表的第一个节点
struct Test t2 = {2, NULL}; // 定义并初始化链表的第二个节点
struct Test t3 = {3, NULL}; // 定义并初始化链表的第三个节点
struct Test t4 = {4, NULL}; // 定义并初始化链表的第四个节点
struct Test t5 = {5, NULL}; // 定义并初始化链表的第五个节点
struct Test t6 = {6, NULL}; // 定义并初始化链表的第六个节点
t1.next = &t2; // 设置t1的next指针,指向t2
t2.next = &t3; // 设置t2的next指针,指向t3
t3.next = &t4; // 设置t3的next指针,指向t4
t4.next = &t5; // 设置t4的next指针,指向t5
t5.next = &t6; // 设置t5的next指针,指向t6
printf("t1到t6的值是:");
printLink(&t1); // 调用printLink函数,从t1开始打印整个链表的数据
return 0;
}
这段代码主要展示了两个结构体的定义以及一个打印链表的函数的实现。 代码的详细解释如下: 1. 头文件<stdio.h>用于包含标准输入输出库。 2. 定义了一个结构体Student,它包含了一个字符指针成员`name`、一个整型成员`age`、一个整型成员aihao和一个指向函数的指针p、以及一个指向结构体自身的指针`next`。 3. 定义了另一个结构体`Test`,它包含了一个整型成员`data`和一个指向结构体自身的指针`next`。 4. 定义了一个名为`printlink`的函数,用于打印链表。这个函数接受一个指向`Test`结构体的指针`head`作为参数。 5. 在`printlink`函数中,声明一个指针`point`,并将其初始化为`head`。 6. 使用`while`循环遍历链表,当`point`指针不为空时,打印当前节点的`data`成员,并将`point`指针移动到下一个节点。 7. 在`main`函数中,声明并初始化了一个整型数组`arry`,并使用`for`循环打印数组中的每个元素。 8. 声明并初始化了六个`Test`类型的结构体变量`t1`到`t6`,并分别赋值给它们的`data`成员。 9. 通过指针的方式将这六个结构体按照顺序连接成链表。 10. 使用`printlink`函数打印链表的数据。 代码的运行结果如下: 1 2 3 use t1 to print three nums 1 2 3 4 5 6 在循环遍历数组部分,数组中的元素被依次打印输出。 在链表部分,通过调用`printlink`函数,可以打印出链表中的所有数据。在这个例子中,链表的数据为`1 2 3 4 5 6`。
#include <stdio.h>
struct Student
{
char *name;
int age;
int aihao;
int (*p)(int age);
struct Student *next;
};
struct Test
{
int data;
struct Test *next;
};
void printlink(struct Test *head)
{
struct Test *point;
point = head;
while (point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
int main()
{
int arry[] = {1,2,3};
for (int i = 0; i < sizeof (arry)/sizeof (arry[0]);i++){
printf("%d ",arry[i]);
}
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
struct Test t6 = {6,NULL};
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
t5.next = &t6;
printf("\nuse t1 to print three nums\n");
//printf("%d %d %d %d\n",t1.data,t1.next->data,t1.next->next->data,t1.next->next->next->data);
printlink(&t1);
return 0;
}
四、链表遍历中的point=point->next
void printlink(struct Test *head)
{
struct Test *point;
point = head;
while (point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
这段代码定义了一个名为`printlink`的函数,用于打印链表中节点的数据。
代码的详细解释如下:
1. 函数的定义为`void printlink(struct Test *head)`,接受一个名为`head`的指向`struct Test`结构体的指针作为参数。
2. 在函数内部,声明了一个名为`point`的指针变量,用于遍历链表。并且将`head`赋值给`point`,确保从链表的起始节点开始遍历。
3. 使用`while`循环来遍历链表,循环条件为`point != NULL`,即当`point`指针不为空时执行循环。
4. 在循环内部,使用`printf`语句打印出当前节点的`data`成员,即当前节点的数据。
5. 将`point`指针移动到下一个节点,这通过`point = point->next`实现。
6. 当链表遍历完成后,跳出循环,并使用`putchar('\n')`打印一个换行,以进行格式化输出。
总结起来,`printlink`函数的作用是接受一个链表的头指针,然后遍历整个链表,逐个打印出链表中节点的数据。
注意:在你提供的代码中,函数`printlink`是针对`struct Test`类型的链表进行操作的。如果要操作其他类型的链表,需要相应地修改函数的参数和结构体定义。
五、统计链表节点个数及链表查找
5、1统计节点个数
这段代码定义了一个名为`getlinkTotalNodeNum`的函数,用于计算链表中节点的总数。
代码的详细解释如下:
1. 函数的定义为`int getlinkTotalNodeNum(struct Test *head)`,接受一个名为`head`的指向`struct Test`结构体的指针作为参数,表示链表的头指针。
2. 在函数内部,声明了一个名为`cnt`的整型变量,用于计数链表中的节点数量,并将其初始化为0。
3. 使用`while`循环遍历链表,循环条件为`head != NULL`,即当当前节点指针`head`不为空时执行循环。
4. 在循环内部,每次循环时将计数器`cnt`加1,表示遇到了一个节点。
5. 将指针`head`移动到下一个节点,这通过`head = head->next`实现。
6. 当链表遍历完成后,跳出循环,并将最终的节点数量`cnt`作为函数的返回值。
总结起来,`getlinkTotalNodeNum`函数的作用是接受一个链表的头指针,然后通过遍历链表的方式计算出链表中节点的总数,并将总数作为函数的返回值返回。
注意:在你提供的代码中,函数`getlinkTotalNodeNum`是针对`struct Test`类型的链表进行操作的。如果要操作其他类型的链表,需要相应地修改函数的参数和结构体定义。
int getlinkTotalNodeNum(struct Test *head)
{
int cnt = 0;
while (head != NULL){
cnt++;
head = head->next;
}
return cnt;
}
int ret = getlinkTotalNodeNum(&t1);
printf("total num = %d\n",ret);
#include <stdio.h>
struct Student
{
char *name;
int age;
int aihao;
int (*p)(int age);
struct Student *next;
};
struct Test
{
int data;
struct Test *next;
};
void printlink(struct Test *head)
{
struct Test *point;
point = head;
while (point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
int getlinkTotalNodeNum(struct Test *head)
{
int cnt = 0;
while (head != NULL){
cnt++;
head = head->next;
}
return cnt;
}
int main()
{
int arry[] = {1,2,3};
for (int i = 0; i < sizeof (arry)/sizeof (arry[0]);i++){
printf("%d ",arry[i]);
}
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
struct Test t6 = {6,NULL};
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
t5.next = &t6;
printf("\nuse t1 to print three nums\n");
//printf("%d %d %d %d\n",t1.data,t1.next->data,t1.next->next->data,t1.next->next->next->data);
printlink(&t1);
int ret = getlinkTotalNodeNum(&t1);
printf("total num = %d\n",ret);
return 0;
}
F:\C-code\scratch.exe
1 2 3
use t1 to print three nums
1 2 3 4 5 6
total num = 6
5、2链表的查找
这段代码定义了一个名为`searchink`的函数,用于在链表中搜索是否存在指定的数据。 代码的详细解释如下: 1. 函数的定义为`int searchink(struct Test *head, int data)`,接受一个名为`head`的指向`struct Test`结构体的指针作为链表的头指针参数,同时接受一个名为`data`的整数参数,表示要搜索的数据。 2. 在函数内部使用`while`循环遍历链表,循环条件为`head != NULL`,即当当前节点指针`head`不为空时执行循环。 3. 在循环内部,使用条件语句`if (head->data == data)`判断当前节点的`data`成员是否等于指定的数据`data`。 4. 如果条件成立,表示找到了匹配的数据,通过`return 1`语句返回值1。 5. 如果条件不成立,则继续遍历下一个节点,将指针`head`移动到下一个节点,这通过`head = head->next`实现。 6. 当遍历完整个链表仍未找到匹配的数据时,函数会自动退出循环,然后结束函数执行,不返回任何值。 总结起来,`searchink`函数的作用是接受一个链表的头指针和一个指定的数据,然后遍历链表,搜索是否存在与指定数据匹配的节点。如果找到匹配的节点,函数返回值1,表示存在匹配的数据;如果未找到匹配的节点,函数不返回任何值。 注意:在你提供的代码中,函数`searchink`是针对`struct Test`类型的链表进行操作的。如果要操作其他类型的链表,需要相应地修改函数的参数和结构体定义。另外,需要考虑在找到匹配的数据时,添加相应的操作来结束函数执行,例如返回一个特殊的值或执行其他逻辑。
int searchink(struct Test *head,int data)
{
while (head != NULL){
if(head->data == data){
return 1;
}
head = head->next;
}
}
ret = searchink(&t1,1);
if(ret == 0){
printf("no 1\n");
} else{
printf("have 1\n");
}
ret = searchink(&t1,8);
if(ret == 0){
printf("no 8\n");
} else{
printf("have 8\n");
}
have 1
no 8
#include <stdio.h>
struct Student
{
char *name;
int age;
int aihao;
int (*p)(int age);
struct Student *next;
};
struct Test
{
int data;
struct Test *next;
};
void printlink(struct Test *head)
{
struct Test *point;
point = head;
while (point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
int getlinkTotalNodeNum(struct Test *head)
{
int cnt = 0;
while (head != NULL){
cnt++;
head = head->next;
}
return cnt;
}
int searchink(struct Test *head,int data)
{
while (head != NULL){
if(head->data == data){
return 1;
}
head = head->next;
}
}
int main()
{
int arry[] = {1,2,3};
for (int i = 0; i < sizeof (arry)/sizeof (arry[0]);i++){
printf("%d ",arry[i]);
}
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
struct Test t6 = {6,NULL};
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
t5.next = &t6;
printf("\nuse t1 to print three nums\n");
//printf("%d %d %d %d\n",t1.data,t1.next->data,t1.next->next->data,t1.next->next->next->data);
printlink(&t1);
int ret = getlinkTotalNodeNum(&t1);
printf("total num = %d\n",ret);
ret = searchink(&t1,1);
if(ret == 0){
printf("no 1\n");
} else{
printf("have 1\n");
}
ret = searchink(&t1,8);
if(ret == 0){
printf("no 8\n");
} else{
printf("have 8\n");
}
return 0;
}
F:\C-code\scratch.exe
1 2 3
use t1 to print three nums
1 2 3 4 5 6
total num = 6
have 1
no 8
进程已结束,退出代码0
六、链表从指定节点后方插入新节点
int insertFromBehind(struct Test *head,int data,struct Test *newNode)
{
struct Test *p = head;
while(p != NULL){
if(p->data == data){
newNode->next = p->next;
p->next = newNode;
return 1;
}
p = p->next;
}
return 0;
}
puts("after insert behind:\n");
insertFromBehind(&t1,3,&newNode);
printlink(&t1);
after insert behind:
1 2 3 100 4 5 6
上面的代码是一个演示如何在链表中指定元素之后插入新节点的例子。 - 首先,定义了一个函数`insertFromBehind`,该函数接受一个指向链表头节点的指针`head`,要插入的数据`data`,以及一个指向新节点的指针`newNode`作为参数。 - 在函数中,我们使用一个指针变量`p`来遍历链表。通过一个循环,我们在链表中找到数据值等于`data`的节点。 - 一旦找到匹配的节点,我们将新节点的`next`指针指向原节点的下一个节点,然后将原节点的`next`指针指向新节点,完成插入操作。 - 最后,函数返回1表示插入成功,如果找不到匹配的节点,则返回0。 在主函数中,我们创建了一个简单的链表,其中节点依次连接起来。 然后,我们创建一个新节点 `newNode`,数据值为100。 接下来,我们调用 `insertFromBehind` 函数,将新节点插入到数据值为3的节点之后。 最后,我们调用 `printlink` 函数,打印链表的所有节点数据,以验证插入操作是否成功。
#include <stdio.h>
struct Test
{
int data;
struct Test *next;
};
int insertFromBehind(struct Test *head,int data,struct Test *newNode)
{
struct Test *p = head;
while(p != NULL){
if(p->data == data){
newNode->next = p->next;
p->next = newNode;
return 1;
}
p = p->next;
}
return 0;
}
void printlink(struct Test *head)
{
struct Test *point;
point = head;
while (point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
int getlinkTotalNodeNum(struct Test *head)
{
int cnt = 0;
struct Test *p = head;
while (p != NULL){
cnt++;
p = p->next;
}
return cnt;
}
int searchink(struct Test *head,int data)
{
while (head != NULL){
if(head->data == data){
return 1;
}
head = head->next;
}
return 0;
}
int main()
{
int arry[] = {1,2,3};
for (int i = 0; i < sizeof (arry)/sizeof (arry[0]);i++){
printf("%d ",arry[i]);
}
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
struct Test t6 = {6,NULL};
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
t5.next = &t6;
struct Test newNode = {100,NULL};
printf("\nuse t1 to print three nums\n");
//printf("%d %d %d %d\n",t1.data,t1.next->data,t1.next->next->data,t1.next->next->next->data);
printlink(&t1);
puts("after insert behind:\n");
insertFromBehind(&t1,3,&newNode);
printlink(&t1);
return 0;
}
after insert behind:
1 2 3 4 5 6 100
after insert behind:
1 100 2 3 4 5 6
七、链表从指定节点前方插入新节点
#include <stdio.h>
struct Test* insertFromfor(struct Test *head, int data, struct Test *newNode2)
{
struct Test *P = head;
while (P != NULL && P->data != data) {
P = P->next;
}
if (P == NULL) {
return NULL; // 没有找到匹配的节点
}
newNode2->next = head;
head = newNode2;
return newNode2;
}
int main()
{
struct Test *head = NULL;
head = &t1;
printlink(head);
struct Test newNode2 = {101,NULL};
head = insertFromfor(head,1,&newNode2);
puts("after insert head:\n");
printlink(head);
return 0;
}
//
// Created by zhonglibo on 2023/7/28.
//
#include <stdio.h>
struct Test
{
int data;
struct Test *next;
};
struct Test* insertFromfor(struct Test *head, int data, struct Test *newNode2)
{
struct Test *P = head;
if(P->data == data){
newNode2->next = head;
return newNode2;
}
while (P->next != NULL){
if(P->next->data == data){
newNode2->next = P->next;
P->next = newNode2;
}
P = P->next;
}
return head;
}
void printlink(struct Test *head)
{
struct Test *point;
point = head;
while (point != NULL){
printf("%d ",point->data);
point = point->next;
}
putchar('\n');
}
int main() {
int arry[] = {1, 2, 3};
for (int i = 0; i < sizeof(arry) / sizeof(arry[0]); i++) {
printf("%d ", arry[i]);
}
struct Test *head = NULL;
struct Test t1 = {1, NULL};
struct Test t2 = {2, NULL};
struct Test t3 = {3, NULL};
struct Test t4 = {4, NULL};
struct Test t5 = {5, NULL};
struct Test t6 = {6, NULL};
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
t5.next = &t6;
head = &t1;
struct Test newNode = {100, NULL};
printf("\nuse t1 to print three nums\n");
//printf("%d %d %d %d\n",t1.data,t1.next->data,t1.next->next->data,t1.next->next->next->data);
//printlink(&t1);
puts("after insert behind:\n");
//insertFromBehind(head, 1, &newNode);
//printlink(head);
struct Test newNode2 = {200, NULL};
head = insertFromfor(head, 1, &newNode2);
puts("after insert head:\n");
printlink(head);
return 0;
}
八、链表删除指定节点
8、1Linux段错调试
gcc link1.c -g
gdb a.out
r
q
y
#include <stdio.h>
#include <stdlib.h>
struct Test {
int data;
struct Test *next;
};
// 打印链表的函数
void printlink(struct Test *head) {
struct Test *point;
point = head;
while (point != NULL) {
printf("%d ", point->data);
point = point->next;
}
putchar('\n');
}
// 删除节点的函数
struct Test* deletNode(struct Test *head, int data) {
struct Test *p = head;
if (p != NULL && p->data == data) {
head = head->next;
free(p);
return head;
}
while (p != NULL && p->next != NULL) {
if (p->next->data == data) {
p->next = p->next->next;
return head;
}
p = p->next;
}
return head;
}
int main() {
struct Test *head = NULL;
struct Test *p = (struct Test *) malloc(sizeof(struct Test));
// 创建节点并连接成链表
p->data = 1;
p->next = (struct Test *) malloc(sizeof(struct Test));
p = p->next;
p->data = 2;
p->next = (struct Test *) malloc(sizeof(struct Test));
p = p->next;
p->data = 3;
p->next = (struct Test *) malloc(sizeof(struct Test));
p = p->next;
p->data = 4;
p->next = (struct Test *) malloc(sizeof(struct Test));
p = p->next;
p->data = 5;
p->next = NULL;
head = p;
printlink(head);
// 删除节点5,并打印链表
head = deletNode(head, 5);
printlink(head);
// 创建新节点并插入链表尾部
struct Test newNode3 = { 103, NULL };
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = &newNode3;
puts("after insert for:\n");
printlink(head);
return 0;
}
这是一段C语言的代码,主要实现了创建一个链表,并对其进行删除和插入操作。
以下是每一行代码的详细解释:
#include <stdio.h>
和#include <stdlib.h>
:包含标准输入输出库和标准库函数。struct Test
:定义了一个结构体类型,包含一个整型数据成员data
和一个指向下一个结构体的指针next
。printlink
函数:打印链表的函数。通过循环遍历链表中的每个节点,并输出节点的数据值。deletNode
函数:删除节点的函数。根据给定的数据值,在链表中查找并删除对应的节点。main
函数:程序的的主函数。首先创建一个空链表head
。然后通过动态分配内存的方式创建五个节点,并将它们连接起来形成一个链表。接着打印链表。然后删除节点5,再次打印链表。最后创建一个新节点,并将其插入到链表的尾部,再次打印链表。具体来说,代码的执行流程如下:
- 首先,声明了一个结构体类型
Test
,它包含一个整型数据成员data
和一个指向下一个结构体的指针next
。- 接下来,定义了一个名为
printlink
的函数,该函数用于打印链表。它接受一个指向链表头节点的指针head
,并通过循环遍历链表中的每个节点,并输出节点的数据值。- 然后,定义了一个名为
deletNode
的函数,该函数用于删除链表中的特定节点。它接受一个指向链表头节点的指针head
和一个整型数据值data
。在函数中,首先定义一个指向头节点的指针p
,如果头节点不为空且数据值等于给定的值,则更新头节点和释放原头节点的内存,并返回新的头节点。如果头节点为空或数据值不等于给定值,则通过循环遍历链表中的每个节点,直到找到目标节点为止。找到目标节点后,更新指向前一个节点的指针的next
指向目标节点的下一个节点,并返回头节点。如果整个链表中都没有找到目标节点,则返回原头节点。- 在
main
函数中,首先声明一个指向链表头节点的指针head
,并将其初始化为空指针。- 接下来,通过动态分配内存的方式创建五个节点,并将它们连接起来形成一个链表。具体来说,首先创建一个节点,并将其数据值设置为1,然后将该节点的
next
指向另一个新创建的节点,以此类推,直到最后一个节点的next
指向空指针为止。- 然后,调用
printlink
函数打印链表。- 接着,调用
deletNode
函数,将数据值为5的节点从链表中删除。- 再次调用
printlink
函数,打印更新后的链表。- 然后,创建一个新的结构体变量
newNode3
,并初始化其数据值为103。- 最后,通过循环找到链表的最后一个节点,并将新节点插入到链表的尾部,再次调用
printlink
函数打印更新后的链表。总结:该代码主要演示了如何创建链表,并在需要时删除和插入节点。通过这些操作,可以动态地修改链表的内容。
九、 链表动态创建之头插法
这段代码是一个简单的链表操作示例。下面是每一行代码的详细解读:
#include <stdio.h>
和#include <stdlib.h>
:这两个头文件包含了所需的输入输出和动态内存分配函数。struct Test
结构体定义:定义了一个包含一个整数类型的数据成员data
和一个指向下一个结构体的指针next
。printlink
函数:该函数用于打印链表中的所有节点数据。它接受一个指向链表头节点的指针head
作为参数,并通过循环遍历链表,依次打印每个节点的数据。gaiLink
函数:该函数用于在链表中查找指定数据的节点,并将其数据更新为新数据。它接受一个指向链表头节点的指针head
,一个要查找的数据data
,和一个要更新为的新数据newdata
。它通过循环遍历链表,查找数据匹配的节点,如果找到则更新节点的数据,并返回 1,表示数据已更新;否则返回 0,表示未找到匹配的节点。insertFromHead
函数:该函数用于在链表头部插入新节点。它接受一个指向链表头节点的指针head
作为参数,并创建一个新的节点,获取用户输入的数据,将新节点的next
指针指向当前的链表的头节点,然后将链表的头节点指针指向新节点,最后返回更新后的链表头节点指针。main
函数:该函数是程序的的主入口。在这个函数中,首先定义一个整型变量i
并初始化为 5,然后创建一个空链表头节点指针head
,并将其初始化为 NULL。接下来使用while
循环来重复执行插入新节点的操作,直到循环条件i-- > 0
不满足为止。每次循环都会调用insertFromHead
函数,将新节点插入到链表的头部。最后,调用printlink
函数打印链表中的所有节点数据。总结:这段代码演示了如何定义链表结构体,创建链表,插入新节点,以及遍历和打印链表中的数据。
#include <stdio.h>
#include <stdlib.h>
struct Test {
int data;
struct Test *next;
};
// 打印链表的函数
void printlink(struct Test *head) {
struct Test *point;
point = head;
while (point != NULL) {
printf("%d ", point->data);
point = point->next;
}
putchar('\n');
}
// 在链表中查找指定数据的节点,并将其数据更新为新数据
int gaiLink(struct Test *head, int data, int newdata) {
while (head != NULL) {
if (head->data == data) {
head->data = newdata;
return 1; // 找到并更新了数据,返回1
}
head = head->next;
}
return 0; // 没有找到数据,返回0
}
// 在链表头部插入新节点的函数
struct Test* insertFromHead(struct Test *head) {
struct Test *newNode;
newNode = (struct Test*)malloc(sizeof(struct Test)); // 分配新节点的内存空间
printf("请输入新节点的数据:\n");
scanf("%d", &(newNode->data));
if (head == NULL) {
newNode->next = head;
head = newNode;
} else {
newNode->next = head;
head = newNode;
}
return head;
}
int main() {
int i = 5;
struct Test *head = NULL;
while (i--> 0) { // 修改为循环条件大于0,避免无限循环
head = insertFromHead(head);
}
printlink(head);
return 0;
}
十、尾插法创建链表
这段代码是一个简单的链表操作示例。下面是每段代码的详细解释:
#include <stdio.h>
和#include <stdlib.h>
:这两个头文件包含了所需的输入输出和动态内存分配函数。struct Test
结构体定义:定义了一个包含一个整数类型的数据成员data
和一个指向下一个结构体的指针next
。printlink
函数:该函数用于打印链表中的所有节点数据。它接受一个指向链表头节点的指针head
作为参数,并通过循环遍历链表,依次打印每个节点的数据。gaiLink
函数:该函数用于在链表中查找指定数据的节点,并将其数据更新为新数据。它接受一个指向链表头节点的指针head
,一个要查找的数据data
,和一个要更新为的新数据newdata
。它通过循环遍历链表,查找数据匹配的节点,如果找到则更新节点的数据,并返回 1,表示数据已更新;否则返回 0,表示未找到匹配的节点。insertFromHead
函数:该函数用于在链表头部插入新节点。它接受一个指向链表头节点的指针head
作为参数,并创建一个新的节点,获取用户输入的数据,将新节点的next
指针指向当前链表的头节点,然后将链表的头指针指向新节点,最后返回更新后的链表头节点指针。creatlink
函数:该函数用于创建链表并返回头节点。它接受一个指向链表头节点的指针head
作为参数。通过一个无限循环,每次循环都为新节点分配内存,并获取用户输入的数据,然后将新节点插入到链表的头部。当用户输入数据为 0 时,跳出循环,返回头节点指针。main
函数:该函数是程序的主入口。在这个函数中,首先定义一个空链表头节点指针head
,并将其初始化为 NULL。然后调用creatlink
函数创建链表,并将返回的头节点指针赋给head
。接下来调用printlink
函数打印链表中的所有节点数据。然后创建一个新的节点t1
,将其数据设置为 1000,将该节点的指针传递给insertFromHead
函数,将新节点插入到链表的头部。最后再次调用printlink
函数打印更新后的链表中的节点数据。总结:这段代码演示了如何定义链表结构体,创建链表,插入新节点,以及遍历和打印链表中的数据。
#include <stdio.h>
#include <stdlib.h>
struct Test {
int data;
struct Test *next;
};
// 打印链表的函数
void printlink(struct Test *head) {
struct Test *point;
point = head;
while (point != NULL) {
printf("%d ", point->data);
point = point->next;
}
putchar('\n');
}
// 在链表中查找指定数据的节点,并将其数据更新为新数据
int gaiLink(struct Test *head, int data, int newdata) {
while (head != NULL) {
if (head->data == data) {
head->data = newdata;
return 1; // 找到并更新了数据,返回1
}
head = head->next;
}
return 0; // 没有找到数据,返回0
}
// 在链表头部插入新节点的函数
struct Test* insertFromHead(struct Test *head, struct Test *newNode) {
if (head == NULL) {
head = newNode;
} else {
newNode->next = head;
head = newNode;
}
return head;
}
// 创建链表并返回头节点的函数
struct Test* creatlink(struct Test *head) {
struct Test *newNode;
while (1) {
newNode = (struct Test *)malloc(sizeof(struct Test));
printf("input your new node data:\n");
scanf("%d", &(newNode->data));
if (newNode->data == 0) {
printf("0 quit\n");
return head;
}
head = insertFromHead(head, newNode);
}
}
int main() {
struct Test *head = NULL;
head = creatlink(head);
printlink(head);
struct Test t1 = { 1000, NULL };
head = insertFromHead(head, &t1);
printlink(head);
return 0;
}
十一、尾插法创建链表
以下是每行代码的解释:
#include <stdio.h>
和#include <stdlib.h>
:这两行代码包含了标准输入输出库和标准库函数的头文件,以便在代码中使用相关的函数和符号。struct Test { int data; struct Test *next; };
:定义了一个结构体类型Test
,其中包含一个整数类型的数据成员data
和一个指向Test
结构体的指针成员next
。void printlink(struct Test *head)
:定义了一个函数printlink
,它接受一个指向Test
结构体的指针head
作为参数,用于打印链表。struct Test* insertFromHead(struct Test *head, struct Test *newNode)
:定义了一个函数insertFromHead
,它接受两个指向Test
结构体的指针head
和newNode
作为参数,用于在链表头部插入新节点。struct Test* insertBehind(struct Test *head, struct Test *newNode)
:定义了一个函数insertBehind
,它接受两个指向Test
结构体的指针head
和newNode
作为参数,用于在链表尾部插入新节点。struct Test* creatlink(struct Test *head)
:定义了一个函数creatlink
,它接受一个指向Test
结构体的指针head
作为参数,用于创建链表并返回头节点。int main()
:定义了主函数,是程序执行的入口。struct Test *head = NULL;
:定义了一个指向Test
结构体的指针head
,并将其初始化为NULL
。head = creatlink(head);
:调用函数creatlink
,将创建的链表头节点赋值给head
。printlink(head);
:调用函数printlink
,打印链表头节点的数据。struct Test t1 = { 1000, NULL };
:定义了一个名为t1
的Test
结构体变量,并将其初始化为1000
和NULL
。head = insertFromHead(head, &t1);
:调用函数insertFromHead
,将t1
插入到链表头部,并将更新后的头节点地址赋值给head
。printlink(head);
:再次调用函数printlink
,打印链表头节点的数据,以查看插入后的链表。struct Test t2 = { 5000, NULL };
:定义了一个名为t2
的Test
结构体变量,并将其初始化为5000
和NULL
。head = insertBehind(head, &t2);
:调用函数insertBehind
,将t2
插入到链表尾部,并将更新后的头节点地址赋值给head
。printlink(head);
:再次调用函数printlink
,打印链表头节点的数据,以查看插入后的链表。return 0;
:返回程序执行结果,表示程序正常结束。以上是每行代码的解释。该代码主要实现了创建链表、在链表头部插入节点、在链表尾部插入节点和打印链表的功能。
#include <stdio.h>
#include <stdlib.h>
struct Test {
int data;
struct Test *next;
};
// 打印链表的函数
void printlink(struct Test *head) {
struct Test *point;
point = head;
while (point != NULL) {
printf("%d ", point->data);
point = point->next;
}
putchar('\n');
}
// 在链表中查找指定数据的节点,并将其数据更新为新数据
int gaiLink(struct Test *head, int data, int newdata) {
while (head != NULL) {
if (head->data == data) {
head->data = newdata;
return 1; // 找到并更新了数据,返回1
}
head = head->next;
}
return 0; // 没有找到数据,返回0
}
// 在链表头部插入新节点的函数
struct Test* insertFromHead(struct Test *head, struct Test *newNode) {
if (head == NULL) {
head = newNode;
} else {
newNode->next = head;
head = newNode;
}
return head;
}
// 在链表尾部插入新节点的函数
struct Test* insertBehind(struct Test *head, struct Test *newNode) {
struct Test *p = head;
if (p == NULL) {
head = newNode;
return head;
}
while (p->next != NULL) {
p = p->next;
}
p->next = newNode;
return head;
}
// 创建链表并返回头节点的函数
struct Test* creatlink(struct Test *head) {
struct Test *newNode;
while (1) {
newNode = (struct Test *)malloc(sizeof(struct Test));
printf("input your new node data:\n");
scanf("%d", &(newNode->data));
if (newNode->data == 0) {
printf("0 quit\n");
return head;
}
head = insertFromHead(head, newNode);
}
}
int main() {
struct Test *head = NULL;
head = creatlink(head);
printlink(head);
struct Test t1 = { 1000, NULL };
head = insertFromHead(head, &t1);
printlink(head);
struct Test t2 = { 5000, NULL };
head = insertBehind(head, &t2);
printlink(head);
return 0;
}