c语言—链表

1、什么是链表

就是数据结构 -> 数据存放(集合)的思想

数组 :每一个元素的地址是连续的。

int arry[10] ={1,2,3,3,4,5,6,7,8,9,10};

这个空间就等于 4*10 = 40个字节。

1个字符 4个字节.

结构体:每一个元素

struct a {

int a ,b;

};

这个结构体空间就是16个字节 8*2;

一个字符 8个字节。

缺点:

不管是数组,还是结构体,他们无法的 其中的数据进行增加、删除和,因为地址是连续的。

链表:

链表的每一项元素都是一个结构体,在内存存储中不是连续的,是通过指针相连。

2.链表入门:
#include <stdio.h> // 引入标准输入输出库

struct Test
{
	int date; // 定义一个整数类型的成员变量 date
	struct Test *next; // 定义一个指向结构体 Test 的指针 next
};

int main()
{
	int i; // 定义一个整数变量 i
	int arry[] = {1, 2, 3}; // 定义一个整数数组 arry,并初始化为 1, 2, 3
	int len = sizeof(arry) / sizeof(arry[0]); // 计算数组 arry 的长度

	for(i = 0; i < len; i++)
	{
		printf("%d", arry[i]); // 循环输出数组 arry 的每个元素
	}
	putchar('\n'); // 输出一个换行符
	
	struct Test t1 = {1, NULL}; // 定义并初始化结构体变量 t1,date 为 1,next 为 NULL
	struct Test t2 = {2, NULL}; // 定义并初始化结构体变量 t2,date 为 2,next 为 NULL
	struct Test t3 = {3, NULL}; // 定义并初始化结构体变量 t3,date 为 3,next 为 NULL
	
	t1.next = &t2; // 将 t1 的 next 指针指向 t2
	t2.next = &t3; // 将 t2 的 next 指针指向 t3
	
	/*
		t1.data 是结构体 t1 中的一个整数成员变量,表示输出第一个整数。
		t1.next->data 是 t1 结构体中指向下一个节点的指针 next 所指节点的整数成员变量,表示输出第二个整数。
		t1.next->next->data 是 t1 结构体中指向下一个节点的指针 next 所指节点中再次指向下一个节点的指针 next 所指节点的整数成员变量,表示输出第三个整数。
	*/
	printf("%d %d %d", t1.date, t1.next->date, t1.next->next->date); // 输出 t1 的 date,t2 的 date,t3 的 date
	
	return 0; // 返回 0,表示程序正常结束
}

3.while 循环输出链表
#include <stdio.h> // 引入标准输入输出库

struct Test
{
	int date; // 定义一个整数类型的成员变量 date
	struct Test *next; // 定义一个指向结构体 Test 的指针 next
};

void printLink(struct Test *head)
{
	struct Test *point;
	point = head;

		while(point != NULL){  //如果当前节点指针 point 不为空 循环,当为空时,循环结束。
		
			printf("%d",point->date);
			point = point->next;
		}
			putchar('\n');
		
		
	
}
int main()
{
	struct Test t1 = {1, NULL}; 
	struct Test t2 = {2, NULL}; 
	struct Test t3 = {3, NULL}; 
	struct Test t4 = {4, NULL}; 
	
	t1.next = &t2; 
	t2.next = &t3; 
	t3.next = &t4; 
	
	printLink(&t1);
	return 0; // 返回 0,表示程序正常结束
}

4.统计链表节点的个数,以及链表查找
#include <stdio.h> // 引入标准输入输出库

struct Test
{
	int date; // 定义一个整数类型的成员变量 date
	struct Test *next; // 定义一个指向结构体 Test 的指针 next
};

void printLink(struct Test *head)
{
	struct Test *point;
	point = head;
	
	while(point != NULL) {  // 如果当前节点指针 point 不为空则循环,当为空时,循环结束
		printf("%d ", point->date); // 输出当前节点的 date
		point = point->next; // 移动到下一个节点
	}
	putchar('\n'); // 输出换行符
}
 //计算链表的节点数
int getLink(struct Test *head)
{
	int cnt = 0; // 计数器初始化为 0
	while(head != NULL) {
		cnt++; // 计数器加 1
		head = head->next; // 移动到下一个节点
	}
	return cnt; // 返回链表的节点个数
}


// 链表查找
int searLink(struct Test *head, int date)
{
	while(head != NULL) {
		if(head->date == date) { // 如果当前节点的 date 等于要查找的 date
			return 1; // 返回 1 表示找到
		}
		head = head->next; // 移动到下一个节点
	}
	return 0; // 返回 0 表示未找到
}

int main()
{
	int i; // 定义一个整数变量 i
	int arry[] = {1, 2, 3}; // 定义一个整数数组 arry,并初始化为 1, 2, 3
	int len = sizeof(arry) / sizeof(arry[0]); // 计算数组 arry 的长度

	for(i = 0; i < len; i++)
	{
		printf("%d ", arry[i]); // 循环输出数组 arry 的每个元素
	}
	putchar('\n'); // 输出一个换行符
	
	struct Test t1 = {1, NULL}; 
	struct Test t2 = {2, NULL}; 
	struct Test t3 = {3, NULL};
	struct Test t4 = {4, NULL}; 
	
	t1.next = &t2; // 设置 t1 的 next 指向 t2
	t2.next = &t3; // 设置 t2 的 next 指向 t3
	t3.next = &t4; // 设置 t3 的 next 指向 t4
	
	
	printLink(&t1); // 打印链表
	
	int ret = getLink(&t1); // 获取链表长度
	printf("%d\n", ret); // 打印链表长度
	
	ret = searLink(&t1, 1); // 查找链表中是否有值为 1 的节点
	if(ret == 0) {
		printf("no 1\n"); // 如果未找到,输出 "no 1"
	} else {
		printf("have 1\n"); // 如果找到,输出 "have 1"
	}
	
	ret = searLink(&t1, 8); // 查找链表中是否有值为 8 的节点
	if(ret == 0) {
		printf("no 8\n"); // 如果未找到,输出 "no 8"
	} else {
		printf("have 8\n"); // 如果找到,输出 "have 8"
	}
	return 0; // 返回 0,表示程序正常结束
}

5.链表从指定节点后方插入新节点
#include <stdio.h> // 引入标准输入输出库

// 定义结构体 Test
struct Test
{
	int date; // 定义一个整数类型的成员变量 date
	struct Test *next; // 定义一个指向结构体 Test 的指针 next
};

// 从链表的指定日期节点之后插入新节点
int insertFromBehind(struct Test *head, int date, struct Test *new) {
    // 定义一个指针p指向链表的头部
    struct Test *p = head;

    // 遍历链表,直到p为空(即到达链表末尾)
    while (p != NULL) {
        // 如果找到日期与指定日期匹配的节点
        if (p->date == date) {
            // 将新节点的next指针指向当前节点的下一个节点
            new->next = p->next;
            // 将当前节点的next指针指向新节点
            p->next = new;
            // 插入成功,返回1
            return 1;
        }

        // 移动指针p到下一个节点
        p = p->next;
    }

    // 如果未找到指定日期的节点,返回0
    return 0;
}

// 打印链表中的所有节点
void printLink(struct Test *head) {
	struct Test *point;
	point = head;
	
	while(point != NULL) {  // 如果当前节点指针 point 不为空则循环,当为空时,循环结束
		printf("%d ", point->date); // 输出当前节点的 date
		point = point->next; // 移动到下一个节点
	}
	putchar('\n'); // 输出换行符
}

// 计算链表的节点数
int getLink(struct Test *head) {
	int cnt = 0; // 计数器初始化为 0
	struct Test *p = head;
	while(p != NULL) {
		cnt++; // 计数器加 1
		p = p->next; // 移动到下一个节点
	}
	return cnt; // 返回链表的节点个数
}

// 链表查找
int searLink(struct Test *head, int date) {
	while(head != NULL) {
		if(head->date == date) { // 如果当前节点的 date 等于要查找的 date
			return 1; // 返回 1 表示找到
		}
		head = head->next; // 移动到下一个节点
	}
	return 0; // 返回 0 表示未找到
}

// 主函数
int main() {
	int i; // 定义一个整数变量 i
	int arry[] = {1, 2, 3}; // 定义一个整数数组 arry,并初始化为 1, 2, 3
	int len = sizeof(arry) / sizeof(arry[0]); // 计算数组 arry 的长度

	// 输出数组 arry 的每个元素
	for(i = 0; i < len; i++) {
		printf("%d ", arry[i]); // 循环输出数组 arry 的每个元素
	}
	putchar('\n'); // 输出一个换行符
	
	// 定义四个结构体 Test 并初始化
	struct Test t1 = {1, NULL}; 
	struct Test t2 = {2, NULL}; 
	struct Test t3 = {3, NULL};
	struct Test t4 = {4, NULL}; 
	
	// 将这些结构体连接成一个链表
	t1.next = &t2; 
	t2.next = &t3; 
	t3.next = &t4; 
	
	// 定义一个新的结构体节点
	struct Test new = {100, NULL};
	
	// 打印链表
	printLink(&t1); 
	
	puts("----\n");
	
	// 插入新的节点到日期为 4 的节点之后
	insertFromBehind(&t1, 4, &new);
	
	// 再次打印链表
	printLink(&t1); 
	
	return 0; 
}

6.1删除头节点,返回链表的头指针
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test
{
	int date; // 定义一个整数类型的成员变量 date
	struct Test *next; // 定义一个指向结构体 Test 的指针 next
};

// 删除节点,返回链表的头指针
struct Test* deletNode(struct Test *head, int data) 
{	
	struct Test *p = head; // 初始化指针 p 指向链表的头节点

	if(p->date == data) { // 如果头节点的 date 字段与 data 值相等
		head = head->next; // 将头节点指向下一个节点
		free(p); // 释放原头节点的内存
		return head; // 返回新的头节点
	}
	
	// 通常还会有更多代码来处理链表中其他节点的删除
	return head; // 当前仅处理头节点匹配的情况,返回头节点
}

// 打印链表中的所有节点
void printLink(struct Test *head) {
	struct Test *point;
	point = head; // 初始化指针 point 指向链表的头节点
	
	while(point != NULL) { // 如果当前节点指针 point 不为空则循环,当为空时,循环结束
		printf("%d ", point->date); // 输出当前节点的 date
		point = point->next; // 移动到下一个节点
	}
	putchar('\n'); // 输出换行符
}

// 主函数
int main() {
	int i; // 定义一个整数变量 i
	int arry[] = {1, 2, 3}; // 定义一个整数数组 arry,并初始化为 1, 2, 3
	int len = sizeof(arry) / sizeof(arry[0]); // 计算数组 arry 的长度

	// 输出数组 arry 的每个元素
	for(i = 0; i < len; i++) {
		printf("%d ", arry[i]); // 循环输出数组 arry 的每个元素
	}
	putchar('\n'); // 输出一个换行符
	
	// 动态分配内存并初始化一个结构体 Test
	struct Test *p = (struct Test*)malloc(sizeof(struct Test));
	p->date = 1; // 设置 p 的 date 字段为 1

	// 定义并初始化其他结构体 Test
	struct Test t2 = {2, NULL}; 
	struct Test t3 = {3, NULL};
	struct Test t4 = {4, NULL}; 
	
	struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head
	
	// 将这些结构体连接成一个链表
	p->next = &t2; // p 的 next 指针指向 t2
	t2.next = &t3; // t2 的 next 指针指向 t3
	t3.next = &t4; // t3 的 next 指针指向 t4
	
	head = p; // 将 head 指向链表的头节点
	
	// 打印链表
	printLink(head); 
	
	puts("----\n"); // 输出分隔符
	
	// 删除链表中 date 字段为 1 的节点
	head = deletNode(head, 1);
	
	// 再次打印链表
	printLink(head); 
	
	return 0; // 返回 0 表示程序成功结束
}

6.2删除指定节点
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test
{
	int date; // 定义一个整数类型的成员变量 date
	struct Test *next; // 定义一个指向结构体 Test 的指针 next
};

// 删除节点,返回链表的头指针
struct Test* deletNode(struct Test *head, int data) 
{	
	struct Test *p = head; // 初始化指针 p 指向链表的头节点

	if(p->date == data) { // 如果头节点的 date 字段与 data 值相等
		head = head->next; // 将头节点指向下一个节点
		free(p); // 释放原头节点的内存
		return head; // 返回新的头节点
	}
	
	while(p->next != NULL){ // 遍历链表,直到链表末尾
		if(p->next->date == data){ // 如果找到节点的 next 的 date 字段与 data 值相等
			struct Test* temp = p->next; // 临时保存找到的节点
			p->next = p->next->next; // 将当前节点的 next 指针指向找到节点的下一个节点
			free(temp); // 释放找到节点的内存
			return head; // 返回链表的头节点
		}
		p = p->next; // 移动到下一个节点
	}
	return head; // 返回链表的头节点
}

// 打印链表中的所有节点
void printLink(struct Test *head) {
	struct Test *point;
	point = head; // 初始化指针 point 指向链表的头节点
	
	while(point != NULL) { // 如果当前节点指针 point 不为空则循环,当为空时,循环结束
		printf("%d ", point->date); // 输出当前节点的 date
		point = point->next; // 移动到下一个节点
	}
	putchar('\n'); // 输出换行符
}

// 主函数
int main() {
	int i; // 定义一个整数变量 i
	int arry[] = {1, 2, 3}; // 定义一个整数数组 arry,并初始化为 1, 2, 3
	int len = sizeof(arry) / sizeof(arry[0]); // 计算数组 arry 的长度

	// 输出数组 arry 的每个元素
	for(i = 0; i < len; i++) {
		printf("%d ", arry[i]); // 循环输出数组 arry 的每个元素
	}
	putchar('\n'); // 输出一个换行符
	
	// 动态分配内存并初始化一个结构体 Test
	struct Test *p = (struct Test*)malloc(sizeof(struct Test));
	p->date = 1; // 设置 p 的 date 字段为 1

	// 定义并初始化其他结构体 Test
	struct Test t2 = {2, NULL}; 
	struct Test t3 = {3, NULL};
	struct Test t4 = {4, NULL}; 
	
	struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head
	
	// 将这些结构体连接成一个链表
	p->next = &t2; // p 的 next 指针指向 t2
	t2.next = &t3; // t2 的 next 指针指向 t3
	t3.next = &t4; // t3 的 next 指针指向 t4
	
	head = p; // 将 head 指向链表的头节点
	
	// 打印链表
	printLink(head); 
	
	puts("----\n"); // 输出分隔符
	
	// 删除链表中 date 字段为 4 的节点
	head = deletNode(head, 4);
	
	// 再次打印链表
	printLink(head); 
	
	return 0; // 返回 0 表示程序成功结束
}

7.1 通过头插法创建一个链表,并打印出链表中的所有节点。用户需要输入三个整数来创建链表的三个节点。
#include <stdio.h> // 引入标准输入输出库
// 创建动态头插法->指定节点数
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test {
    int date;              // 定义一个整数类型的成员变量 date
    struct Test *next;     // 定义一个指向结构体 Test 的指针 next
};

// 打印链表中的所有节点
void printLink(struct Test *head) {
    struct Test *point;
    point = head; // 初始化指针 point 指向链表的头节点
    
    // 遍历链表
    while(point != NULL) { // 如果当前节点指针 point 不为空则循环,当为空时,循环结束
        printf("%d ", point->date); // 输出当前节点的 date
        point = point->next; // 移动到下一个节点
    }
    putchar('\n'); // 输出换行符
}

// 从头插法创建链表节点
struct Test* creatFromHead(struct Test *head) {    
    struct Test *new;

    // 为新节点分配内存
    new = (struct Test *)malloc(sizeof(struct Test));
    printf("请输入新的 NEW\n");
    // 读取新节点的 date 值
    scanf("%d", &(new->date));
    new->next = NULL; // 将新节点的 next 指针设置为 NULL,防止指向野指针
    
    // 如果链表为空,则新节点为头节点
    if(head == NULL) {
        head = new;
    } else {
        // 否则,将新节点插入链表头部
        new->next = head;
        head = new;
    }
    
    return head;
}

// 主函数
int main() {
    int i = 3;
    struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head

    // 创建指定数量的链表节点
    while(i--) {
        head = creatFromHead(head); 
    }
    
    // 打印链表
    printLink(head); 
    return 0; // 返回 0 表示程序成功结束
}

7.2通过头插法创建一个链表,并打印出链表中的所有节点。用户可以输入一系列整数来创建链表,当输入 0 时,链表创建结束。
#include <stdio.h> // 引入标准输入输出库
// 创建动态头插法 —>指定个数,当输入 0 时,链表创建结束
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test {
    int date;              // 定义一个整数类型的成员变量 date
    struct Test *next;     // 定义一个指向结构体 Test 的指针 next
};

// 打印链表中的所有节点
void printLink(struct Test *head) {
    struct Test *point;
    point = head; // 初始化指针 point 指向链表的头节点
    
    // 遍历链表
    while(point != NULL) { // 如果当前节点指针 point 不为空则循环,当为空时,循环结束
        printf("%d ", point->date); // 输出当前节点的 date
        point = point->next; // 移动到下一个节点
    }
    putchar('\n'); // 输出换行符
}

// 从头插法创建链表
struct Test* creatFromHead(struct Test *head) {    
    struct Test *new;
    while(1) {
        // 为新节点分配内存
        new = (struct Test *)malloc(sizeof(struct Test));
        printf("请输入新的 NEW\n");
        // 读取新节点的 date 值
        scanf("%d", &(new->date));
        new->next = NULL; // 将新节点的 next 指针设置为 NULL,防止指向野指针
        
        // 如果输入的 date 为 0,则退出循环
        if(new->date == 0) {
            printf("o quit\n");
            return head;
        }
        
        // 如果链表为空,则新节点为头节点
        if(head == NULL) {
            head = new;
        } else {
            // 否则,将新节点插入链表头部
            new->next = head;
            head = new;
        }
    }
    return head;
}

// 主函数
int main() {
    int i = 3;
    struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head

    // 创建链表
    head = creatFromHead(head); 
    
    // 打印链表
    printLink(head); 
    return 0; // 返回 0 表示程序成功结束
}

注:

1.scanf("%d",&(new->date));为什么要使用取地址符号
  • new 是一个指向结构体 Test 的指针:
  • struct Test *new
  • new = (struct Test *)malloc(sizeof(struct Test));
  • new->date 是一个整数变量:
  • new->date;
  • scanf 需要知道 new->date 变量在内存中的地址,以便将输入的整数存储在 new->date 中:
  • scanf("%d", &(new_node->date));

通过 & 运算符,scanf 获得了 new_node->date 的地址,从而可以直接在内存中修改该位置存储的值。

2.new->next = NULL; 的目的是初始化新节点的 next 指针,使其指向 NULL,防止成为野指针。
7.3动态字节前插入数据_函数调用插入新的结构体
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test
{
    int date; // 保存日期数据
    struct Test *next; // 指向下一个节点的指针
};

// 将新节点插入链表头部的函数
struct Test *inserLink(struct Test *head, struct Test *new_node)	
{		
    if(head == NULL) { // 如果链表为空
        head = new_node; // 新节点成为链表的头节点
    } else { // 如果链表不为空
        new_node->next = head; // 新节点的 next 指向当前的头节点
        head = new_node; // 新节点成为新的头节点
    }
    return head;		
}

// 创建链表的函数
struct Test *creatLink(struct Test *head)
{
    struct Test *new_node;
    while(1) { // 循环创建新节点
        new_node = (struct Test *)malloc(sizeof(struct Test)); // 分配新节点的内存
        printf("please enter new date\n");
        scanf("%d", &(new_node->date)); // 输入新节点的 date
        new_node->next = NULL; // 初始化新节点的 next 为 NULL
        if(new_node->date == 0) { // 如果输入的 date 为 0,结束输入
            printf("over\n");
            free(new_node); // 释放新节点的内存
            return head; // 返回链表的头节点
        }
        head = inserLink(head, new_node); // 将新节点插入链表头部
    }
}

// 打印链表中的所有节点
void printLink(struct Test *head) {
    struct Test *point;
    point = head;

    while(point != NULL) { // 遍历链表
        printf("%d ", point->date); // 打印节点的 date
        point = point->next; // 移动到下一个节点
    }
    putchar('\n'); // 换行
}

// 主函数
int main() {
    struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head,初始化为 NULL

    struct Test t1 = {100, NULL}; // 定义一个结构体 Test 实例 t1,并初始化

    // 输出分隔符
    puts("----\n"); 

    head = creatLink(head); // 创建链表
    printLink(head); // 打印链表

    head = inserLink(head, &t1); // 将 t1 插入链表头部
    printf("Inserted OK\n");
    printLink(head); // 打印链表

    return 0; 
}

8.1通过尾插插法创建一个链表,并打印出链表中的所有节点。
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test {
    int date;              // 定义一个整数类型的成员变量 date
    struct Test *next;     // 定义一个指向结构体 Test 的指针 next
};

// 打印链表中的所有节点
void printLink(struct Test *head) {
    struct Test *point; // 定义一个指向结构体 Test 的指针 point
    point = head; // 初始化指针 point 指向链表的头节点
    
    // 遍历链表
    while(point != NULL) { // 当当前节点指针 point 不为空时循环
        printf("%d ", point->date); // 输出当前节点的 date
        point = point->next; // 将指针 point 移动到下一个节点
    }
    putchar('\n'); // 输出换行符
}

// 动态尾插法创建链表
struct Test* creatFromHead(struct Test *head) 
{
    struct Test *new; // 定义一个指向结构体 Test 的指针 new,用于创建新节点
    struct Test *p = head; // 定义一个指向结构体 Test 的指针 p,并将其初始化为链表的头节点
    
    while(1) { // 无限循环,直到遇到 break 结束
        new = (struct Test *)malloc(sizeof(struct Test)); // 动态分配新节点的内存空间
        printf("please enter new date\n"); // 提示用户输入新节点的 date
        scanf("%d", &(new->date)); // 将用户输入的数据存储到新节点的 date 成员中
        new->next = NULL; // 初始化新节点的 next 指针为 NULL
        
        if(new->date == 0) { // 如果用户输入的 date 为 0,则表示结束输入
            printf("over new date\n"); // 输出提示信息
            free(new); // 释放新节点的内存空间
            return head; // 返回链表的头指针,结束函数
        }
        
        if(head == NULL) { // 如果链表为空
            head = new; // 新节点成为链表的头节点
        } else { // 如果链表不为空
            p = head; // 将指针 p 重新指向链表的头节点
            while(p->next != NULL) { // 找到链表的最后一个节点
                p = p->next; // 移动指针 p 到下一个节点
            }
            p->next = new; // 将新节点连接到链表的最后一个节点的 next 指针上
        }
    }
    
    return head; // 返回链表的头指针(理论上不会执行到这里,因为 while 是无限循环)
}
   
// 主函数
int main() {
    int i = 3; // 定义一个整型变量 i,但未在后续代码中使用
    
    struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head,并初始化为 NULL

    // 创建链表
    head = creatFromHead(head); 
    
    // 打印链表
    printLink(head); 
    
    return 0; // 返回 0 表示程序成功结束
}

else 中的 p=head;

函数的开头已经声明了 struct Test *p = head;,但这个声明只是在第一次while进入循环时有效。当你在循环中遇到 if (head == NULL) 条件并且设置了 head = new; 后,变量 p 没有更新。因此,你需要在 else 分支中重新设置 p = head;,以便在链表非空的情况下从头开始遍历链表。

每次进入循环时,你都需要从链表的头部开始遍历,以便找到链表的末尾位置并将新节点插入到链表的末尾。如果你不在 else 分支中重新设置 p = head;,p 会在第一次插入后保持在链表的尾部,导致后续插入操作无法正确地遍历链表。

else {
p = head; // 将 p 指针重新指向链表的头节点
while(p->next != NULL) { // 遍历链表直到找到最后一个节点
p = p->next;
}
p->next = new; // 将新节点 new 连接到链表的末尾
}

解释:
1. 逻辑背景:
    • 当链表不为空(即 head != NULL)并且要插入新节点时,需要将新节点插入到链表的末尾。
    • p 是一个辅助指针,用来遍历链表找到最后一个节点。
2. 步骤详解:
    • p = head;:将指针 p 设置为链表的头节点,这样从头开始遍历链表。
    • while(p->next != NULL):循环遍历链表,直到找到最后一个节点。条件 p->next != NULL 确保在循环结束时,p 指向链表中最后一个节点。
    • p->next = new;:将新节点 new 连接到 p 指向的最后一个节点的 next 指针上,使得新节点成为链表中的新的最后一个节点。
8.2通过尾插插法创建一个链表,并打印出链表中的所有节点。
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,包含 malloc 和 free 函数

// 定义结构体 Test
struct Test {
    int date;              // 定义一个整数类型的成员变量 date
    struct Test *next;     // 定义一个指向结构体 Test 的指针 next
};

// 打印链表中的所有节点
void printLink(struct Test *head) {
    struct Test *point; // 定义一个指向结构体 Test 的指针 point
    point = head; // 初始化指针 point 指向链表的头节点
    
    // 遍历链表
    while(point != NULL) { // 当当前节点指针 point 不为空时循环
        printf("%d ", point->date); // 输出当前节点的 date
        point = point->next; // 将指针 point 移动到下一个节点
    }
    putchar('\n'); // 输出换行符
}

// 插入新节点到链表末尾
struct Test *inserLink(struct Test *head, struct Test *new) {
    struct Test *p = head; // 定义一个指向结构体 Test 的指针 p,并初始化为链表的头节点
    
    if(p == NULL) { // 如果链表为空
        head = new; // 新节点成为链表的头节点
        return head; // 返回头节点
    }
    
    while(p->next != NULL) { // 找到链表的最后一个节点
        p = p->next; // 移动指针 p 到下一个节点
    }
    
    p->next = new; // 将新节点连接到链表的最后一个节点的 next 指针上
    
    return head; // 返回头节点
}

// 动态尾插法创建链表
struct Test* creatFromHead(struct Test *head) {
    struct Test *new; // 定义一个指向结构体 Test 的指针 new,用于创建新节点
    
    while(1) { // 无限循环,直到遇到 break 结束
        new = (struct Test *)malloc(sizeof(struct Test)); // 动态分配新节点的内存空间
        printf("please enter new date\n"); // 提示用户输入新节点的 date
        scanf("%d", &(new->date)); // 将用户输入的数据存储到新节点的 date 成员中
        new->next = NULL; // 初始化新节点的 next 指针为 NULL
        
        if(new->date == 0) { // 如果用户输入的 date 为 0,则表示结束输入
            printf("over new date\n"); // 输出提示信息
            free(new); // 释放新节点的内存空间
            return head; // 返回链表的头指针,结束函数
        }
        
        head = inserLink(head, new); // 调用插入函数将新节点插入到链表的末尾
    }
    
    return head; // 返回链表的头指针(理论上不会执行到这里,因为 while 是无限循环)
}
   
// 主函数
int main() {
    int i = 3; // 定义一个整型变量 i,但未在后续代码中使用
    
    struct Test *head = NULL; // 定义一个指向结构体 Test 的指针 head,并初始化为 NULL

    // 创建链表
    head = creatFromHead(head); 
    
    // 打印链表
    printf("Created linked list:\n");
    printLink(head); 
    
    // 插入额外节点
    struct Test t1 = {100, NULL}; // 创建一个额外的节点 t1
    head = inserLink(head, &t1); // 将节点 t1 插入到链表的末尾
    printf("After inserting additional node:\n");
    printLink(head); 
    
    return 0; // 返回 0 表示程序成功结束
}

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值