C语言链表——增删改查

2023-10-27

目录

一、链表的概念

1.1 什么是链表:

二、链表和数组的区别:

2.1 链表和数组的优缺点:

        2.1.1 数组的优缺点:

        2.1.2 链表的优缺点:

三、链表的静态添加和动态遍历:

四、统计链表节点个数及链表查找

五、链表插入

5.1 链表从指定节点后方插入新节点:

5.2 链表从指定节点前方插入新节点:

六、链表删除指定节点

七、改变链表指定节点的数据

八、动态创建链表

8.1 动态创建链表之头插法:

8.2 动态创建链表之尾插法:

九、链表增删改查


一、链表的概念

1.1 什么是链表:

  • 链表是一种数据结构,是一种数据存放的思想.

二、链表和数组的区别:

  • 数组静态分配内存,链表动态分配内存

  • 数组在内存中是连续的,链表是不连续的

  • 数组利用下标定位,链表通过遍历定位元素

  • 数组插入和删除需要移动其他元素,链表的插入或删除不需要移动其他元素

2.1 链表和数组的优缺点:

2.1.1 数组的优缺点:

  • 随机访问性比较强,可以通过下标进行快速定位。

  • 查找速度快

  • 插入和删除的效率低,需要移动其他元素。

  • 会造成内存的浪费,因为内存是连续的,所以在申请数组的时候就必须规定内存的大小,如果不合适,就会造成内存的浪费。

  • 内存空间要求高,创建一个数组,必须要有足够的连续内存空间。

  • 数组的大小是固定的,在创建数组的时候就已经规定好,不能动态拓展。

2.1.2 链表的优缺点:

  • 插入和删除的效率高,只需要改变指针的指向就可以进行插入和删除。

  • 内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。

  • 查找的效率低,因为链表是从第一个节点向后遍历查找。

#include <stdio.h>

struct Test
{
        int data;			//存放的数据
        struct Test *nest;	//下一个节点的地址
};

int main()
{
        int i;
        int len;
        int arr[3] = {1,2,3};

        len = sizeof(arr)/sizeof(arr[0]);
        for(i=0; i<len; i++){
                printf("%d ",arr[i]);
        }
        putchar('\n');

        struct Test t1 = {1,NULL};
        struct Test t2 = {2,NULL};
        struct Test t3 = {3,NULL};

        t1.nest = &t2;
        t2.nest = &t3;

        printf("use t1 to print three nums\n");
        printf("%d %d %d\n",t1.data,t1.nest->data,t1.nest->nest->data);
        return 0;
}
/*
CLC@Embed_Learn:~/lianbiao$ gcc link.c -o link
CLC@Embed_Learn:~/lianbiao$ ./link
1 2 3 
use t1 to print three nums
1 2 3
*/

三、链表的静态添加和动态遍历:

#include <stdio.h>

struct Test
{
        int data;			//数据
        struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *hand)
{
        struct Test *point;	

        point = hand;						//point指向链表头
        while(point != NULL){				//遍历到链表尾巴NULL时,循环结束
                printf("%d ",point->data);	//输出当前节点data的值
                point = point->nest;		//point指向下一个节点
        }
        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.nest = &t2;	//将节点t2的地址赋值给t1节点的nest
        t2.nest = &t3;	//将节点t3的地址赋值给t2节点的nest
        t3.nest = &t4;	//将节点t4的地址赋值给t3节点的nest

        printf("use t1 to ptint four nums\n");
        printLink(&t1);	//把链表头传到printLink函数中去
        return 0;
}
/*
CLC@Embed_Learn:~/lianbiao$ gcc link1.c -o link1
CLC@Embed_Learn:~/lianbiao$ ./link1
use t1 to ptint four nums
1 2 3 4 

*/

四、统计链表节点个数及链表查找

#include <stdio.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *hand)
{
	struct Test *point;
	
	point = hand;					//point指向链表头		
	while(point != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",point->data);	//输出当前节点data的值
		point = point->nest;		//point指向下一个节点
	}
	putchar('\n');
}

//统计链表节点个数函数
int getLinkTotalNodeNum(struct Test *hand)
{
	int cnt = 0;
	struct Test *point;
	
	point = hand;					//point指向链表头	
	while(point != NULL){			//遍历到链表尾巴NULL时,循环结束
		cnt++;
		point = point->nest;		//point指向下一个节点
	}
	return cnt;
}

//查找链表函数
int searchLink(struct Test *hand, int data)
{
	struct Test *point;
	
	point = hand;					//point指向链表头	
	while(point != NULL){			//遍历到链表尾巴NULL时,循环结束
		if(point->data == data){	//如果当前节点的数据和输入的数据一样
			return 1;				//找到就返回1
		}
		point = point->nest;		//point指向下一个节点
	}
	return 0;						//没有找到就返回0
}

int main()
{
	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};
	
	t1.nest = &t2;		//将节点t2的地址赋值给t1节点的nest
	t2.nest = &t3;		//将节点t3的地址赋值给t2节点的nest
	t3.nest = &t4;		//将节点t4的地址赋值给t3节点的nest
	t4.nest = &t5;		//将节点t5的地址赋值给t4节点的nest
	
	printf("链表动态输出:\n");
	printLink(&t1);		//把链表头传到printLink函数中去
	
	int ret = getLinkTotalNodeNum(&t1);
	printf("链表的节点个数是:%d\n",ret);
	
	ret = searchLink(&t1,1);	//函数返回最终结果
	if(ret == 0){
		printf("没有找到1\n");
	}else{
		printf("找到1了\n");
	}
	
	ret = searchLink(&t1,8);	//函数返回最终结果
	if(ret == 0){
		printf("没有找到8\n");
	}else{
		printf("找到8了\n");
	}
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_lb_bianli.c

E:\code\一阶段C语言\链表>a.exe
链表动态输出:
1 2 3 4 5
链表的节点个数是:5
找到1了
没有找到8
*/

五、链表插入

  • 关于链表的插入有两种方式:

  • 第一种:从指定节点后方插入新节点

  • 第二种:从指定指点前方插入新节点

5.1 链表从指定节点后方插入新节点:

#include <stdio.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *hand)
{
	struct Test *point;
	
	point = hand;					//point指向链表头		
	while(point != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",point->data);	//输出当前节点data的值
		point = point->nest;		//point指向下一个节点
	}
	putchar('\n');
}

//从指定节点后方插入新节点
int insertFromBehind(struct Test *hand, int data, struct Test *new)
{
	struct Test *p = hand;
	
	while(p != NULL){
		if(p->data == data){	//判断当前节点是不是指定节点
			new->nest = p->nest;//把新节点的next指向指定节点的下一个节点(这边要注意顺序不能换,否则链表会断掉)
			p->nest = new;		//再把指定节点的next指向新节点
			return 1;
		}
		p = p->nest;			//p指向下一节点
	}
	return 0;
}

int main()
{
    struct Test *hand = 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};
	
	t1.nest = &t2;		//将节点t2的地址赋值给t1节点的nest
	t2.nest = &t3;		//将节点t3的地址赋值给t2节点的nest
	t3.nest = &t4;		//将节点t4的地址赋值给t3节点的nest
	t4.nest = &t5;		//将节点t5的地址赋值给t4节点的nest
    
    hand = &t1;
    struct Test new = {100,NULL};	//定义一个新节点
	
	printf("链表动态输出:\n");
	printLink(hand);		//把链表头传到printLink函数中去

    int ret = insertFromBehind(hand, 3, &new);	//把链表头,要插入的位置,和新节点的地址传递过去
	if(ret == 1){
		printf("插入成功!\n");
	}else{
		printf("插入失败!\n");
	}
	
	printLink(hand);	//把链表头传过去,打印链表
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_指定节点后方插入新节点.c

E:\code\一阶段C语言\链表>a.exe
链表动态遍历:
1 2 3 4 5
插入成功!
1 2 3 100 4 5
*/

5.2 链表从指定节点前方插入新节点:

如果要在指定节点前插入新节点的话,需要考虑两种情况:

  1. 在第一个节点前插入新节点

  2. 在中间指定节点前插入新节点

#include <stdio.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *hand)
{
	struct Test *p = hand;		//p指向链表头
						
	while(p != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",p->data);	//输出当前节点data的值
		p = p->nest;			//p指向下一个节点
	}
	putchar('\n');
}

//链表在指定节点前方插入新节点
struct Test* insertFromfront(struct Test *hand, int data, struct Test *new)
{
	struct Test *p = hand;
	//在头节点插入(链表头会改变)
	if(p->data == data){//判断指定的节点是不是头节点
		new->nest = p;	//让新节点的next指向p
		printf("第一个节点前插入成功,链表头发生改变!\n");
		return new;		//现在new是新的链表头,return到main函数
	}
	//在中间指定节点前插入
	while(p->nest != NULL){			//因为这里是从中间节点插入,所以会从第二个节点开始遍历链表,直到链表尾NULL时停止
		if(p->nest->data == data){	//判断当前节点是不是指定节点
			new->nest = p->nest;	//让要插入新节点的next指向p->next(就是当前节点的下一个节点)
			p->nest = new;			//在让当前节点next指向要插入的新节点new
			printf("插入成功!\n");
			return hand;			//把链表头return回main函数
		}
		p = p->nest;				//使p指向下一节点
	}
	printf("插入失败!\n");
	return hand;
}

int main()
{
	struct Test *hand = 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};
	
	t1.nest = &t2;	//将节点t2的地址赋值给t1节点的nest
	t2.nest = &t3;	//将节点t3的地址赋值给t2节点的nest
	t3.nest = &t4;	//将节点t4的地址赋值给t3节点的nest
	t4.nest = &t5;	//将节点t5的地址赋值给t4节点的nest
	
	hand = &t1;					//把链表头的地址赋值给hand
	printf("动态输出链表:\n");
	printLink(hand);			//把链表头传过去,打印链表
	
	struct Test new = {100,NULL};//创建一个新节点new
	
	hand = insertFromfront(hand,1,&new);//把链表头,要插入的位置,和新节点new的地址传过去,返回链表头
	printf("在第一个节点前插入一个新节点:\n");
	printLink(hand);
	
	struct Test new2 = {200,NULL};//创建一个新节点new2
	
	hand = insertFromfront(hand,2,&new2);//把链表头,要插入的位置,和新节点new的地址传过去,返回链表头
	printf("在链表中间指定节点前插入一个新节点:\n");
	printLink(hand);
	
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_指定节点前方插入新节点.c

E:\code\一阶段C语言\链表>a.exe
动态输出链表:
1 2 3 4 5
第一个节点前插入成功,链表头发生改变!
在第一个节点前插入一个新节点:
100 1 2 3 4 5
插入成功!
在链表中间指定节点前插入一个新节点:
100 1 200 2 3 4 5
*/

六、链表删除指定节点

  • 链表删除指定节点的两种情况:

  1. 判断要删除的节点是不是第一个节点,如果是第一个节点,直接改链表头,让第二个节点成为新的链表头

  2. 要删除的节点如果不是第一个结点的话,把要删除节点的前一个节点的nest越过要删除的节点,然后指向要删除的节点下一个节点

  • 现在链表是静态创建的,如果链表是动态创建的话,记得把删除节点内存通过free函数释放掉,防止内存泄漏

#include <stdio.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *hand)
{
	struct Test *p = hand;		//p指向链表头
						
	while(p != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",p->data);	//输出当前节点data的值
		p = p->nest;			//p指向下一个节点
	}
	putchar('\n');
}

//链表删除指定节点
struct Test* deleteNode(struct Test *hand, int data)
{
	struct Test *p = hand;
	//删除第一个节点
	if(p->data == data){				//判断要删除的节点是不是头节点
		p = p->nest;					//让p指向下一个节点
		printf("成功删除第一个节点,链表头发生改变!\n");
		return p;						//把新的链表头return回去
	}
	//删除其他节点
	while(p->nest != NULL){				//从第二个节点开始遍历链表
		if(p->nest->data == data){		//判断当前节点是不是要删除的节点
			p->nest = p->nest->nest;	//把要删除节点的前一个节点的next越过要删除的节点,然后指向要删除节点的下一个节点
			printf("成功删除指定节点!\n");
			return hand;				//把链表头return回去
		}
		p = p->nest;					//p指向下一个节点
	}
    return hand;
}

int main()
{
	struct Test *hand = 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};
	
	t1.nest = &t2;	//将节点t2的地址赋值给t1节点的nest
	t2.nest = &t3;	//将节点t3的地址赋值给t2节点的nest
	t3.nest = &t4;	//将节点t4的地址赋值给t3节点的nest
	t4.nest = &t5;	//将节点t5的地址赋值给t4节点的nest
	
	hand = &t1;					//把链表头的地址赋值给hand
	printf("动态输出链表:\n");
	printLink(hand);			//把链表头传过去,打印链表
	
	hand = deleteNode(hand,3);	//把链表头,和要删除第几个节点传过去
	printf("链表动态输出:\n");
	printLink(hand);			//把链表头传过去,打印链表
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_链表删除指定节点.c

E:\code\一阶段C语言\链表>a.exe
链表动态输出:
1 2 3 4 5
成功删除第一个节点,链表头发生改变!
链表动态输出:
2 3 4 5

E:\code\一阶段C语言\链表>gcc demo_链表删除指定节点.c

E:\code\一阶段C语言\链表>a.exe
链表动态输出:
1 2 3 4 5
成功删除指定节点!
链表动态输出:
1 2 4 5

E:\code\一阶段C语言\链表>gcc demo_链表删除指定节点.c

E:\code\一阶段C语言\链表>a.exe
链表动态输出:
1 2 3 4 5
成功删除指定节点!
链表动态输出:
1 2 3 4

E:\code\一阶段C语言\链表>gcc demo_链表删除指定节点.c

E:\code\一阶段C语言\链表>a.exe
链表动态输出:
1 2 3 4 5
成功删除指定节点!
链表动态输出:
1 2 4 5
*/

七、改变链表指定节点的数据

#include <stdio.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *hand)
{
	struct Test *p = hand;		//p指向链表头
						
	while(p != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",p->data);	//输出当前节点data的值
		p = p->nest;			//p指向下一个节点
	}
	putchar('\n');
}

//改变链表指定节点的数据
int gaiLink(struct Test *hand, int data, int newData)
{
	struct Test *p = hand;
	
	while(p != NULL){
		if(p->data == data){		//找到指定节点
			p->data = newData;		//改变指定节点的数据
			return 1;
		}
		p = p->nest;
	}
	return 0;
}

int main()
{
	int newData;	//要改变的数据
	int node;		//指定节点
	struct Test *hand = 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};
	
	t1.nest = &t2;	//将节点t2的地址赋值给t1节点的nest
	t2.nest = &t3;	//将节点t3的地址赋值给t2节点的nest
	t3.nest = &t4;	//将节点t4的地址赋值给t3节点的nest
	t4.nest = &t5;	//将节点t5的地址赋值给t4节点的nest
	
	hand = &t1;					//把链表头的地址赋值给hand
	printf("动态输出链表:\n");
	printLink(hand);			//把链表头传过去,打印链表
	
	printf("请输入你要改那个节点的数据:\n");
	scanf("%d",&node);
	printf("请输入你要改的数据:\n");
	scanf("%d",&newData);
	
	int ret = gaiLink(hand,node,newData);//把链表头,指定节点和要改变的数据传过去
	if(ret == 1){
		printf("数据改变成功!\n");
	}else{
		printf("数据改变失败!\n");
	}
	printf("数据改变之后输出链表:\n");
	printLink(hand);
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_改变链表指定节点的数据.c

E:\code\一阶段C语言\链表>a.exe
链表动态遍历输出:
1 2 3 4 5
请输入你要改那个节点的数据:
2
请输入你要改的数据:
100
数据改变成功!
数据改变之后输出链表:
1 100 3 4 5
*/

八、动态创建链表

  • 动态创建链表有两种方式:

  1. 头插法

  2. 尾插法

8.1 动态创建链表之头插法:

  • 刚开始是没有链表的,需要我们动态创建:我们动态创建一个新节点,如果head是NULL那么就让我们的新节点当作链表头,每次创建的新节点插在链表头之前,让新节点当作链表头

#include <stdio.h>
#include <stdlib.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *head)
{
	struct Test *p = head;		//p指向链表头
						
	while(p != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",p->data);	//输出当前节点data的值
		p = p->nest;			//p指向下一个节点
	}
	putchar('\n');
}

//动态创建链表之头插法
struct Test* insertFromHead(struct Test *head, struct Test *new)
{
	if(head == NULL){		//当没有链表的时候
		head = new;			//创建的第一个节点当作链表头
	}else{					//如果链表有其他节点存在
		new->nest = head;	//创建的新节点的nest指向后面的节点
		head = new;			//新节点当作链表头
	}
	return head;			//return链表头
}

//动态创建链表
struct Test* creatLink(struct Test *head)
{
	struct Test *new;
	
	while(1){
		new = (struct Test *)malloc(sizeof(struct Test));	//创建一个新节点
		new->nest = NULL;									//新节点的nest指向NULL,否则遍历输出链表会出错
		printf("创建新节点完成,请输入新节点的数据:\n");	
		scanf("%d",&(new->data));							//输入新节点的数据
		if(new->data == 0){									//判断输入新节点的数据是否为0
			printf("0 quit\n");
			free(new);										//释放节点数据为0的节点
			return head;									//停止创建链表,return链表头
		}
		head = insertFromHead(head,new);					//新节点当作链表头
	}
	return head;											//return链表头
}

int main()
{
	struct Test *head = NULL;
	
	head = creatLink(head);					//head指向链表头
	printf("动态创建链表完成,动态输出链表:\n");
	printLink(head);
    
    struct Test t1 = {100,NULL};
	head = insertFromHead(head,&t1);
	printf("随时可以将创建的新节点通过头插法插入到链表中:\n");
	printLink(head);
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_链表动态创建之头插法.c

E:\code\一阶段C语言\链表>a.exe
创建新节点完成,请输入新节点的数据:
1
创建新节点完成,请输入新节点的数据:
2
创建新节点完成,请输入新节点的数据:
3
创建新节点完成,请输入新节点的数据:
0
0 quit
动态创建链表完成,动态输出链表:
3 2 1
随时可以将创建的新节点通过头插法插入到链表中:
100 3 2 1
*/

8.2 动态创建链表之尾插法:

  • 刚开始是没有链表的,需要我们动态创建:我们动态创建一个新节点,创建的第一个节点当作链表头,然后每一次创建的新节点插在链表最后一个节点的nest中

#include <stdio.h>
#include <stdlib.h>

struct Test
{
	int data;			//数据
	struct Test *nest;	//指向同类型的指针
};

//链表动态遍历输出
void printLink(struct Test *head)
{
	struct Test *p = head;		//p指向链表头
						
	while(p != NULL){			//遍历到链表尾巴NULL时,循环结束
		printf("%d ",p->data);	//输出当前节点data的值
		p = p->nest;			//p指向下一个节点
	}
	putchar('\n');
}

//动态创建链表之头插法
struct Test* insertBehind(struct Test *head, struct Test *new)
{
	struct Test *p = head;
	
	if(head == NULL){	//当没有链表的时候
		head = new;		//创建的第一个节点当作链表头
		return head;	//return链表头
	}
	
	while(p->nest != NULL){	//遍历到最后一个节点
		p = p->nest;		//p指向下一个节点
	}
	p->nest = new;			//创建的新节点插入到最后一个节点的nest中
	
	return head;			//return链表头
}

//动态创建链表
struct Test* creatLink(struct Test *head)
{
	struct Test *new;
	
	while(1){
		new = (struct Test *)malloc(sizeof(struct Test));	//创建一个新节点
		new->nest = NULL;									//新节点的nest指向NULL,否则遍历输出链表会出错
		printf("创建新节点完成,请输入新节点的数据:\n");
		scanf("%d",&(new->data));							//输入新节点的数据
		if(new->data == 0){									//判断输入新节点的数据是否为0
			printf("0 quit\n");
			free(new);										//释放节点数据为0的节点
			return head;									//停止创建链表,return链表头
		}
		head = insertBehind(head,new);						//每次动态创建的新节点通过尾插法插入到链表中
	}
	return head;											//return链表头
}

int main()
{
	struct Test *head = NULL;
	
	head = creatLink(head);
	printf("动态创建链表完成,动态输出链表:\n");
	printLink(head);
	
	struct Test t1 = {100,NULL};
	head = insertBehind(head,&t1);
	printf("随时可以将创建的新节点通过尾插法插入到链表中:\n");
	printLink(head);
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_链表动态创建之尾插法.c -g

E:\code\一阶段C语言\链表>a.exe
创建新节点完成,请输入新节点的数据:
1
创建新节点完成,请输入新节点的数据:
2
创建新节点完成,请输入新节点的数据:
3
创建新节点完成,请输入新节点的数据:
0
0 quit
动态创建链表完成,动态输出链表:
1 2 3
随时可以将创建的新节点通过尾插法插入到链表中:
1 2 3 100
*/

九、链表增删改查

#include <stdio.h>
#include <stdlib.h>

struct Test
{
	int data;
	struct Test *nest;
};

//动态遍历链表
void printLink(struct Test *head)
{
	struct Test *p = head;
	
	while(p != NULL){
		printf("%d ",p->data);
		p = p->nest;
	}
	putchar('\n');
}

//动态创建链表之尾插法
struct Test* insertFromBehind(struct Test *head, struct Test *new)
{
	struct Test *p = head;
	
	if(head == NULL){
		head = new;
		return new;
	}
	
	while(p->nest != NULL){
		p = p->nest;
	}
	p->nest = new;
	
	return head;
}

//动态创建链表
struct Test* creatLink(struct Test *head)
{
	struct Test *new;
	
	while(1){
		new = (struct Test *)malloc(sizeof(struct Test));
		new->nest = NULL;
		printf("动态创建新节点完成,请输入新节点data的数据:\n");
		scanf("%d",&(new->data));
		if(new->data == 0){
			printf("0 quit\n");
			free(new);
			return head;
		}
		head = insertFromBehind(head,new);
	}
	return head;
}

//统计链表节点个数
int getLinkTotalNodeNum(struct Test *head)
{
	struct Test *p = head;
	int cnt = 0;
	
	while(p != NULL){
		cnt++;
		p = p->nest;
	}
	return cnt;
}

//查找链表节点
int searchLink(struct Test *head, int data)
{
	struct Test *p = head;
	
	while(p != NULL){
		if(p->data == data){
			return 1;
		}
		p = p->nest;
	}
	return 0;
}

//在指定节点后面插入新节点
int insertFromBehind2(struct Test *head, int data, struct Test *new)
{
	struct Test *p = head;
	
	while(p != NULL){
		if(p->data == data){
			new->nest = p->nest;
			p->nest = new;
			return 1;
		}
		p = p->nest;
	}
	return 0;
}

//在指定节点前方插入新节点
struct Test* insertFromfront(struct Test *head, int data, struct Test *new)
{
	struct Test *p = head;
	
	if(p->data == data){
		new->nest = p;
		printf("在第%d个节点前面插入新节点OK,链表头发生变化!\n",data);
		return new;
	}
	
	while(p->nest != NULL){
		if(p->nest->data == data){
			new->nest = p->nest;
			p->nest = new;
			printf("在指定节点%d前面插入新节点OK\n",data);
			return head;
		}
		p = p->nest;
	}
	return head;
}

//链表删除指定节点
struct Test* deleteNode(struct Test *head, int data)
{
	struct Test *p = head;
	
	if(p->data == data){
		head = p->nest;
		free(p);
		printf("链表的第%d个节点删除完毕,链表头发生变化!\n",data);
		return head;
	}
	
	while(p->nest != NULL){
		if(p->nest->data == data){
			p->nest = p->nest->nest;
			printf("链表的第%d个节点删除完毕!\n",data);
			return head;
		}
		p = p->nest;
	}
	return head;
}

//修改链表指定节点的数据
int gaiLink(struct Test *head, int data, int newData)
{
	struct Test *p = head;
	
	while(p != NULL){
		if(p->data == data){
			p->data = newData;
			return 1;
		}
		p = p->nest;
	}
	return 0;
}

int main()
{
	int cmd;
	int newData;
	struct Test *head = NULL;
	
	head = creatLink(head);
	printf("链表动态创建完成,遍历输出:\n");
	printLink(head);
	
	int ret = getLinkTotalNodeNum(head);
	printf("链表的节点个数:%d\n",ret);
	
	printf("请输入你要查找哪一个节点数据:\n");
	scanf("%d",&cmd);
	ret = searchLink(head,cmd);
	if(ret == 1){
		printf("可以找到:%d\n",cmd);
	}else{
		printf("找不到%d\n",cmd);
	}
	printf("请输入你要查找哪一个节点数据:\n");
	scanf("%d",&cmd);
	ret = searchLink(head,cmd);
	if(ret == 1){
		printf("可以找到:%d\n",cmd);
	}else{
		printf("找不到%d\n",cmd);
	}
	
	struct Test new = {100,NULL};
	printf("请输入你要插在哪一个节点后面:\n");
	scanf("%d",&cmd);
	ret = insertFromBehind2(head,cmd,&new);
	if(ret == 1){
		printf("在指定节点%d后面插入新节点OK\n",cmd);
	}else{
		printf("在指定节点%d后面插入新节点失败\n",cmd);
	}
	printf("在指定节点后面插入新节点后遍历输出链表:\n");
	printLink(head);
	
	struct Test new2 = {200,NULL};
	printf("请输入你要插在哪一个节点的前面:\n");
	scanf("%d",&cmd);
	head = insertFromfront(head,cmd,&new2);
	printf("链表在指定节点前方插入新节点OK,遍历输出:\n");
	printLink(head);
	
	printf("请输入你要删除哪一个节点:\n");
	scanf("%d",&cmd);
	head = deleteNode(head,cmd);
	printf("链表删除指定节点后,输出链表:\n");
	printLink(head);
	
	printf("请输入你要改哪一个节点data的数据:\n");
	scanf("%d",&cmd);
	printf("请输入要更改的数据:\n");
	scanf("%d",&newData);
	ret = gaiLink(head,cmd,newData);
	if(ret == 1){
		printf("指定节点的数据修改成功!\n");
	}else{
		printf("指定节点的数据修改失败!\n");
	}
	printf("链表修改指定节点data的数据后,遍历输出链表:\n");
	printLink(head);
	return 0;
}
/*
E:\code\一阶段C语言\链表>gcc demo_链表.c -g

E:\code\一阶段C语言\链表>a.exe
动态创建新节点完成,请输入新节点data的数据:
1
动态创建新节点完成,请输入新节点data的数据:
2
动态创建新节点完成,请输入新节点data的数据:
3
动态创建新节点完成,请输入新节点data的数据:
4
动态创建新节点完成,请输入新节点data的数据:
5
动态创建新节点完成,请输入新节点data的数据:
0
0 quit
链表动态创建完成,遍历输出:
1 2 3 4 5
链表的节点个数:5
请输入你要查找哪一个节点数据:
1
可以找到:1
请输入你要查找哪一个节点数据:
8
找不到8
请输入你要插在哪一个节点后面:
5
在指定节点5后面插入新节点OK
在指定节点后面插入新节点后遍历输出链表:
1 2 3 4 5 100
请输入你要插在哪一个节点的前面:
3
在指定节点3前面插入新节点OK
链表在指定节点前方插入新节点OK,遍历输出:
1 2 200 3 4 5 100
请输入你要删除哪一个节点:
2
链表的第2个节点删除完毕!
链表删除指定节点后,输出链表:
1 200 3 4 5 100
请输入你要改哪一个节点data的数据:
200
请输入要更改的数据:
1000
指定节点的数据修改成功!
链表修改指定节点data的数据后,遍历输出链表:
1 1000 3 4 5 100
*/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言链表——增删改查 的相关文章

  • 第14天-ElasticSearch环境配置,构建检索服务及商品上架到ES库

    1 ElasticSearch概念 官网介绍 https www elastic co cn what is elasticsearch 官网学习文档 https www elastic co guide en elasticsearch
  • 三、Vite 文件系统 import.meta.glob

    文章目录 一 参考 二 import meta glob 介绍 2 1 import meta glob 的作用 2 2 eager true 一次引入所有 2 3 Glob 导入注意事项 三 遍历 import meta glob 文件系
  • 水库大坝安全管理主要问题和维护措施

    水库大坝作为防灾减灾 解决水资源流失和供需矛盾的重要利民工程 对于维护社会稳定 确保社会经济持续发展具有非常重要的作用 但由于我国大部分水库都建设于 20世纪 70 80 年代 如山东省棘洪滩水库其建设开工时间为1986 年 当时我国经济条
  • Spark数据类型SparseMatrix

    SparseMatrix Spark的mllib包中提供了机器学习的两种基本数据类型 DenseMatrix 稠密 和 SparseMatrix 稀疏 在初始化对象的时候可以使用Matrices伴生对象产生 先看下示例代码 import o
  • Linux-------------DNS域名解析:正反解析

    DNS域名解析 DNS简介 前期准备 正方解析实验 正向解析实验 反向解析实验 常见错误 修改resolv conf 修改hostname 检查DNS是否为ip地址 归纳总结 DNS简介 域名管理系统DNS Domain Name Syst
  • Pentaho Report Designer 入门教程(二)

    Pentaho Report Designer 入门教程 二 采用Pentaho Report Designer5 1版本 也是最新的版本 一 安装和介绍 介绍部分内容略 首先安装jdk 并配置java相关环境变量 下载pentaho re

随机推荐

  • stm32学习总结:2、搭建基于CLion的stm32开发环境

    stm32学习总结 2 搭建基于CLion的stm32开发环境 文章目录 stm32学习总结 2 搭建基于CLion的stm32开发环境 1 前言 2 相关工具和环境准备 2 1 STM32CubeMX 前置工程创建工具 2 2 CLion
  • 敏捷:什么是用户故事(User Story)

    摘要 一件用户通过系统完成他一个有价值的目标 买一罐饮料 的事 这样的过程就叫 用户案例 user case 或者 用户故事 user story 本文描述了敏捷开发的技巧 如何以用户故事管理项目 什么是用户故事 user story 假定
  • 内网渗透-frp 用于内网穿透的基本配置和使用

    frp 用于内网穿透的基本配置和使用 文章目录 frp 用于内网穿透的基本配置和使用 前言 frps frpc 后记 参考 前言 frp 是一个专注于内网穿透的高性能的反向代理应用 支持 TCP UDP HTTP HTTPS 等多种协议 可
  • 【开源介绍】命令行的艺术( the-art-of-command-line )

    1 概述 转载 命令行的艺术 the art of command line
  • Blob数据类型、数据库事务

    1 Bolb是二进制长对象的意思 通常用于存储大文件 通过二进制数据保存到数据库里 并可以从数据库里恢复指定文件 2 如果需要将图片插入数据库 不能通过普通的SQL语句完成 Bolb常量无法表示 所以将Bolb数据插入数据库需要使用Prep
  • 合成孔径SAR卫星影像专业术语

    转载自 http www kosmos image com index php m content c index a show catid 73 id 4132 目录 Across track Active Remote Sensing
  • 初学机器学习:直观解读KL散度的数学概念

    选自thushv com 作者 Thushan Ganegedara 机器之心编译 机器学习是当前最重要的技术发展方向之一 近日 悉尼大学博士生 Thushan Ganegedara 开始撰写一个系列博客文章 旨在为机器学习初学者介绍一些基
  • 深度学习(Deep Learning)读书思考六:循环神经网络一(RNN)

    概述 循环神经网络 RNN Recurrent Neural Network 是神经网络家族中的一员 擅长于解决序列化相关问题 包括不限于序列化标注问题 NER POS 语音识别等 RNN内容比较多 分成三个小节进行介绍 内容包括RNN基础
  • QT窗体间传值总结之Signal&Slot

    在写程序时 难免会碰到多窗体之间进行传值的问题 依照自己的理解 我把多窗体传值的可以使用的方法归纳如下 1 使用QT中的Signal Slot机制进行传值 2 使用全局变量 3 使用public形式的函数接口 4 使用QT中的Event机制
  • 独立进程使用django模型(django.setup()使用)

    文章目录 独立进程使用django模型 独立进程使用django模型 步骤 django setup RuntimeError populate isn t reentrant 独立进程使用django模型报错 Apps aren t lo
  • 提升Postern代理性能的五个小技巧

    在使用Postern代理时 如何提高其性能是许多用户关注的问题 本文将分享一些针对Postern代理进行优化的技巧和建议 帮助更好地利用该工具并获得更出色的网络体验 Postern是一个功能强大且灵活易用的Android应用程序 可实现全局
  • 智能指针auto_prt的使用(c++学习笔记)

    c 中如果要申请资源一般用到new 最后释放资源delete 如果我们在delete之前就退出了函数呢 看下面的代码 cpp view plain copy include
  • 2 指定目录编译

    1 目录结构 指定目录编译 go build o bin calc1 exe day01 package example main 转载于 https www cnblogs com jec1999 p 9822834 html
  • TCP数据的传输过程

    TCP数据的传输过程 TCP Transmission Control Protocol 传输控制协议 是一种面向连接的 可靠的 基于字节流的通信协议 数据在传输前要建立连接 传输完毕后还要断开连接 客户端在收发数据前要使用 connect
  • Spark集群运行问题

    spark输出太多warning messages WARN Executor 2 block locks were not released by TID Lock release errors occur frequently in e
  • 阿里云对象存储oss费用明细

    https www aliyun com price product spm a311a 7996332 0 0 137630803P2qTh oss detail 最终决定 阿里云割韭菜 弃用选择业界其他便宜的 第二年阿里云只给你个续费
  • java操作svn--部分方法

    package com svnutil import java io File import java text DateFormat import java util ArrayList import java util Collecti
  • Fedora12 编译s3c2416 U-Boot1.3.4的Makefile和头文件

    复制Makefile到 和smdk2416 h到include configs 执行 make distclean make smdk2416 config make C Copyright 2007 2008 Jong pill Lee
  • matlab练习程序(Canny边缘检测)

    我可没直接调用系统函数 要是那样就太水了 其实我的matlab代码很容易就能翻译成c c 的 canny边缘检测一共四个部分 1 对原图像高斯平滑 2 对高斯平滑后的图像进行sobel边缘检测 这里需要求横的和竖的还有联合的 所以一共三个需
  • C语言链表——增删改查

    目录 一 链表的概念 1 1 什么是链表 二 链表和数组的区别 2 1 链表和数组的优缺点 2 1 1 数组的优缺点 2 1 2 链表的优缺点 三 链表的静态添加和动态遍历 四 统计链表节点个数及链表查找 五 链表插入 5 1 链表从指定节