15_链表

知识点1【链表的排序(选择法)】0-1(了解)在这里插入图片描述

void sort_link(STU *head)

{

	//1、判断链表是否存在

	if(NULL == head)

	{

		printf("link not found\n");

		return;

	}

	else

	{

		STU *p_i = head;//i=0 

		while(p_i->next != NULL)//i<n-1  外层循环

		{

			STU *p_min = p_i;//min = i;

			STU *p_j = p_min->next;//j = min+1

			while(p_j != NULL)//j<n  内层循环

			{

				

				//寻找成员num最小值的 节点

				if(p_min->num > p_j->num)//if(arr[min] > arr[j])

					p_min = p_j;//min = j

				p_j = p_j->next;//j++

			

			}


			if(p_min != p_i)//min != i

			{

				//只交换数据域(1、节点内容整体交换   2、只交换指针域)

				//1、节点内容整体交换(数据域交换第1次   指针域交换第1次)

				STU tmp;

				tmp = *p_i;

				*p_i = *p_min;

				*p_min = tmp;


				//2、只交换指针域(指针域交换第2次)

				tmp.next = p_i->next;

				p_i->next = p_min->next;

				p_min->next = tmp.next;

			}



			p_i = p_i->next;//i++

		}

		

	}

	

}

知识点2【双向循环链表】(了解)0-2
main.c

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

//定义一个双向循环链表的节点类型

typedef struct stu

{

	//数据域

	int num;

	char name[32];

	int age;


	//指针域

	struct stu *next;//指向下一个节点

	struct stu *pre;//指向前一个节点

}STU;


extern STU* insert_link(STU *head, STU tmp);

extern void print_link(STU *head);

extern STU* search_link(STU *head, char *name);

extern STU* delete_link(STU *head, int num);

extern STU* free_link(STU *head);


int main(int argc,char *argv[])

{

	char name[32]="";

	int num = 0;

	int n =0;//保存学生的个数

	int i=0;

	STU *head = NULL;

	STU *ret = NULL;

	

	printf("请输入学员的个数:");

	scanf("%d", &n);

	

	for(i=0;i<n;i++)

	{

		STU tmp;

		printf("请输入第%d个学员的信息:\n",i+1);

		scanf("%d %s %d", &tmp.num, tmp.name, &tmp.age);

	

		//插入一个节点

		head = insert_link(head, tmp);

	}


	//遍历整个链表

	print_link(head);


	//查找指定节点

	printf("请输入要查找的用户名:");

	scanf("%s",name);

	

	//查找中...

#if 1

	ret = search_link(head, name);

	if(ret == NULL)

	{

		printf("没有找到与%s相关的节点信息\n", name);

	}

	else

	{

		printf("查找到的信息为:%d %s %d\n", ret->num, ret->name,ret->age);

	}

#endif

	//删除指定节点 num

	printf("请输入要删除的学号:");

	scanf("%d", &num);

	head = delete_link(head, num);


	//遍历整个链表

	print_link(head);


	//释放整个链表

	head = free_link(head);


	//遍历整个链表

	print_link(head);

	

	return 0;

}


//头部之前插入

STU* insert_link(STU *head, STU tmp)

{

	//1、为插入的节点pi申请空间

	STU *pi = (STU *)calloc(1,sizeof(STU));

	//2、将tmp的值 赋值给 *pi

	*pi = tmp;

	

	//3、判断链表是否存在

	if(head == NULL)//链表不存在

	{

		head = pi;

		pi->next = head;

		pi->pre = head;

	}

	else//链表存在(头部之前插入)

	{

		pi->next = head;

		pi->pre = head->pre;

		head->pre->next = pi;

		head->pre = pi;

		head = pi;

	}


	return head;

}


#if 1

void print_link(STU *head)

{

	//判断链表是否存在

	if(head == NULL)

	{

		printf("link not found\n");

		return;

	}

	else//链表存在

	{

		STU *pb = head;

		do

		{

			//访问节点内容

			printf("num=%d, name=%s, age=%d\n", pb->num,pb->name,pb->age);

			//pb指向下一个节点

			pb = pb->next;

		}while(pb != head);

	}

	return;

}

#endif

#if 0

void print_link(STU *head)

{

	//判断链表是否存在

	if(head == NULL)

	{

		printf("link not found\n");

	}

	else//链表存在

	{

		STU *pb = head;//pb指向头结点

		STU *pf = head->pre;//pf指向了尾节点


		do

		{

			if(pb == pf)//相遇 只需要打印pf或pb中任何一个信息就够了

			{

				printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);

				break;

			}

			printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);

			printf("num=%d,name=%s,age=%d\n", pf->num,pf->name,pf->age);


			pb = pb->next;//next方向的移动

			pf = pf->pre;//pre方向的移动

		}while( pb->pre != pf );//pf和pb不能 擦肩而过

	

	}

}


#endif


STU* search_link(STU *head, char *name)

{

	//判断链表是否存在

	if(head == NULL)

	{

		return NULL;

	}

	else//链表存在

	{

		STU *pb = head;//指向头结点

		STU *pf = head->pre;//指向的是尾节点

		printf("pb = %p\n", pb);

		printf("pf = %p\n", pf);

		printf("pb->pre = %p\n", pb->pre);



		while( (strcmp(pb->name,name) != 0) && (strcmp(pf->name,name)!=0) && (pb != pf) )

		{

			printf("##pb->name=%s##\n",pb->name);

			printf("##pf->name=%s##\n",pf->name);

			pb=pb->next;//next方向移动

			pf=pf->pre;//pf方向移动


			if(pb->pre == pf)

			{

				break;

			}

		}


		if(strcmp(pb->name,name) == 0)

		{

			

			return pb;

		}

		else if(strcmp(pf->name,name)==0)

		{

			return pf;

		}	

	}


	return NULL;

}


STU* delete_link(STU *head, int num)

{

	//判断链表是否存在

	if(head == NULL)

	{

		printf("link not found\n");

		return head;

	}

	else

	{

		STU *pb = head;//指向头节点

		STU *pf = head->pre;//指向尾节点

		

		//逐个节点寻找删除点

		while((pb->num != num) && (pf->num != num) && (pf != pb))

		{

			pb = pb->next;//next方向移动

			pf = pf->pre;//pre方向移动

			if(pb->pre == pf)

				break;

		}


		if(pb->num == num)//删除pb指向的节点

		{


			if(pb == head)//删除头节点

			{

				if(head == head->next)

				{

					free(pb);

					head = NULL;

				}

				else

				{

					head->next->pre = head->pre;

					head->pre->next = head->next;

					head = head->next;

					free(pb);

				}

				

			}

			else//删除中尾部节点

			{

				pb->pre->next = pb->next;

				pb->next->pre = pb->pre;

				free(pb);

			}

		}

		else if(pf->num == num)//删除pf指向的节点

		{

	

			if(pf == head)//删除头节点

			{

				if(head == head->next)

				{

					free(pf);

					head = NULL;

				}

				else

				{

					head->next->pre = head->pre;

					head->pre->next = head->next;

					head = head->next;

					free(pf);

				}

			}

			else//删除中尾部节点

			{

				pf->pre->next = pf->next;

				pf->next->pre = pf->pre;

				free(pf);

			}

		}

		else

		{

			printf("未找到%d相关的节点信息",num);

		}

	}


	return head;

}


STU* free_link(STU *head)

{

	if(head == NULL)//链表为空

	{

		printf("link not found\n");

		return NULL;

	}

	else//链表存在

	{

		STU *pb = head;

		STU *tmp;

		do

		{

			tmp = pb;

			pb = pb->next;

			free(tmp);

		}while(pb != head);

	}


	return NULL;

}

1、认识双向 循环 链表在这里插入图片描述2、双链表 插入在这里插入图片描述

//头部之前插入

STU* insert_link(STU *head, STU tmp)

{

	//1、为插入的节点pi申请空间

	STU *pi = (STU *)calloc(1,sizeof(STU));

	//2、将tmp的值 赋值给 *pi

	*pi = tmp;

	

	//3、判断链表是否存在

	if(head == NULL)//链表不存在

	{

		head = pi;

		pi->next = head;

		pi->pre = head;

	}

	else//链表存在(头部之前插入)

	{

		pi->next = head;

		pi->pre = head->pre;

		head->pre->next = pi;

		head->pre = pi;

		head = pi;

	}


	return head;

}

3、链表的遍历
单向遍历

void print_link(STU *head)

{

	//判断链表是否存在

	if(head == NULL)

	{

		printf("link not found\n");

		return;

	}

	else//链表存在

	{

		STU *pb = head;

		do

		{

			//访问节点内容

			printf("num=%d, name=%s, age=%d\n", pb->num,pb->name,pb->age);

			//pb指向下一个节点

			pb = pb->next;

		}while(pb != head);

	}

	return;

}

双向遍历:1-1

void print_link(STU *head)

{

	//判断链表是否存在

	if(head == NULL)

	{

		printf("link not found\n");

	}

	else//链表存在

	{

		STU *pb = head;//pb指向头结点

		STU *pf = head->pre;//pf指向了尾节点


		do

		{

			if(pb == pf)//相遇 只需要打印pf或pb中任何一个信息就够了

			{

				printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);

				break;

			}

			printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);

			printf("num=%d,name=%s,age=%d\n", pf->num,pf->name,pf->age);


			pb = pb->next;//next方向的移动

			pf = pf->pre;//pre方向的移动

		}while( pb->pre != pf );//pf和pb不能 擦肩而过

	

	}

}

4、双向链表的查找

STU* search_link(STU *head, char *name)

{

	//判断链表是否存在

	if(head == NULL)

	{

		return NULL;

	}

	else//链表存在

	{

		STU *pb = head;//指向头结点

		STU *pf = head->pre;//指向的是尾节点

		printf("pb = %p\n", pb);

		printf("pf = %p\n", pf);

		printf("pb->pre = %p\n", pb->pre);



		while( (strcmp(pb->name,name) != 0) && (strcmp(pf->name,name)!=0) && (pb != pf) )

		{

			printf("##pb->name=%s##\n",pb->name);

			printf("##pf->name=%s##\n",pf->name);

			pb=pb->next;//next方向移动

			pf=pf->pre;//pf方向移动


			if(pb->pre == pf)

			{

				break;

			}

		}


		if(strcmp(pb->name,name) == 0)

		{

			

			return pb;

		}

		else if(strcmp(pf->name,name)==0)

		{

			return pf;

		}	

	}


	return NULL;

}

5、双向链表 删除指定节点1-2在这里插入图片描述在这里插入图片描述

STU* delete_link(STU *head, int num)

{

	//判断链表是否存在

	if(head == NULL)

	{

		printf("link not found\n");

		return head;

	}

	else

	{

		STU *pb = head;//指向头节点

		STU *pf = head->pre;//指向尾节点

		

		//逐个节点寻找删除点

		while((pb->num != num) && (pf->num != num) && (pf != pb))

		{

			pb = pb->next;//next方向移动

			pf = pf->pre;//pre方向移动

			if(pb->pre == pf)

				break;

		}


		if(pb->num == num)//删除pb指向的节点

		{


			if(pb == head)//删除头节点

			{

				if(head == head->next)//链表只有一个节点

				{

					free(pb);

					head = NULL;

				}

				else

				{

					head->next->pre = head->pre;

					head->pre->next = head->next;

					head = head->next;

					free(pb);

				}

				

			}

			else//删除中尾部节点

			{

				pb->pre->next = pb->next;

				pb->next->pre = pb->pre;

				free(pb);

			}

		}

		else if(pf->num == num)//删除pf指向的节点

		{

	

			if(pf == head)//删除头节点

			{

				if(head == head->next)//链表只有一个节点

				{

					free(pf);

					head = NULL;

				}

				else

				{

					head->next->pre = head->pre;

					head->pre->next = head->next;

					head = head->next;

					free(pf);

				}

			}

			else//删除中尾部节点

			{

				pf->pre->next = pf->next;

				pf->next->pre = pf->pre;

				free(pf);

			}

		}

		else

		{

			printf("未找到%d相关的节点信息",num);

		}

	}


	return head;

}

6、释放这个链表节点(了解)

STU* free_link(STU *head)

{

	if(head == NULL)//链表为空

	{

		printf("link not found\n");

		return NULL;

	}

	else//链表存在

	{

		STU *pb = head;

		STU *tmp;

		do

		{

			tmp = pb;

			pb = pb->next;

			free(tmp);

		}while(pb != head);

	}


	return NULL;

}

知识点3【结构的浅拷贝 和深拷贝】(了解)
1、知识点的引入(指针变量 作为 结构体的成员)
在这里插入图片描述

typedef struct

{

	int num;

	char *name;//指针变量作为 结构体的成员

}DATA;

void test01()

{

	DATA data={100,"hehehehaha"};

	printf("%d\n",sizeof(DATA));//8字节


	printf("num = %d\n",data.num);

	//指针变量作为结构体的成员 保存的是空间的地址

	printf("name = %s\n",data.name);

}

2、指针变量 作为结构体的成员 操作前 必须有合法的空间

void test02()

{

	DATA data;

	printf("%d\n",sizeof(DATA));


	printf("num = %d\n",data.num);

	//指针变量 作为结构体的成员 操作前 必须有合法的空间

	//data.name = "hehe";

	//给name 事先申请 一块 堆区空间

	data.name = (char *)calloc(1,10);

	strcpy(data.name,"hahaha");

	printf("name = %s\n",data.name);


	//如果name指向堆区空间 一定要记得释放

	if(data.name != NULL)

	{

		free(data.name);

		data.name = NULL;

	}

}

原理图分析:在这里插入图片描述3、指针变量 作为结构体的成员 结构体变量间的赋值操作 容易导致“浅拷贝”发生在这里插入图片描述

void test03()

{

	DATA data1;

	DATA data2;


	data1.num = 100;

	data1.name = (char *)calloc(1,10);

	strcpy(data1.name,"my data");

	printf("data1:num = %d, name = %s\n",data1.num, data1.name);


	//指针变量 作为结构体的成员 结构体变量间的赋值操作 容易导致“浅拷贝”发生

	data2 = data1;//“浅拷贝”

	printf("data2: num = %d, name = %s\n",data2.num, data2.name);


	if(data1.name != NULL)

	{

		free(data1.name);

		data1.name = NULL;

	}

	

	if(data2.name != NULL)

	{

		free(data2.name);

		data2.name = NULL;

	}

}

运行结果 出现段错误在这里插入图片描述

发布了20 篇原创文章 · 获赞 0 · 访问量 34

猜你喜欢

转载自blog.csdn.net/weixin_45992045/article/details/104679200