细讲链表(看完会有所收获)

目录

1.链表和函数指针

1.1链表的相关概念

1.1.1data域和指针域

1.2为什么要学习链表

链表和数组的区别

1.3分类

1.3.1动态链表和静态链表

1.3.2带头链表和不带头链表

1.3.3单向链表、双向链表、循环链表等

1.4基本操作


1.链表和函数指针

1.1链表的相关概念

  • 链表是一种常用的数据结构,它通过指针将一些数据节点,连接成一个数据链,相对于数组,链表具有更好的动态性(非顺序存储)
  • 数据域用来存储数据,指针域用于建立与下一个结点的联系

1.1.1data域和指针域

1.2为什么要学习链表

链表和数组的区别

数组:一次性分配一块连续的存储区域

  • 优点:随机访问元素效率高
  • 缺点:需要分配一块连续的存储区域(很大区域,有可能分配失败);删除和插入某个元素效率低

链表:现实生活的灯笼

  • 优点:不需要一块连续的存储区域,删除和插入某个元素效率高
  • 缺点:随机访问元素效率低

1.3分类

1.3.1动态链表和静态链表

  • 静态链表:所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放。
  • 动态链表:指在程序执行过程中从无到有建立一个个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相连的关系

1.3.2带头链表和不带头链表

1.3.3单向链表、双向链表、循环链表等

1.4基本操作

  • 静态链表

//静态链表
#include<stdio.h>
typedef struct Node
{
	int data;//数据域
	char name[10];
	struct Node* next;//指针域
}Node;
int main()
{
	//初始化三个结构体变量
	Node s1 = { 1,"mike", NULL };
	Node s2 = { 2,"lisa",NULL };
	Node s3 = { 3,"cater",NULL };

	s1.next = &s2;//s1的next指针指向s2
	s2.next = &s3;
	s3.next = NULL;//尾结点

	Node* p = &s1;

	while (p != NULL)
	{
		printf("data=%d,name=%s\n", p->data, p->name);

		//结点往后移动一位
		p = p->next;
	}
	printf("\n");
	return 0;
}
  • 动态链表
  1. 建立带有头结点的单向链表:编写函数SListCreat,建立带有头结点的单向链表,循环创建结点,结点数据域中的数值从键盘输入,以-1作为输入结束标志。链表的头结点地址由函数值返回。
  2. 顺序访问链表中各个结点的数据域:编写函数SListPrint,顺序输出单向链表各项数据域中的内容。
  3. 在单向链表中插入结点:编写函数SListNodeInsert,功能:在值为x的结点前,插入值为y的结点;若值为x的结点不存在,则插在表尾。
  4. 删除单向链表中的结点:编写函数SListNodeDel,删除值为x的结点。
  5. 清空链表。
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
	int id;
	struct Node* next;
}Node;
//创建头结点
//链表的头结点由函数值返回
Node* SListCreat()
{
	Node* head = NULL;

	//头结点作为标志,不存储有效数据
	head = (Node*)malloc(sizeof(Node));
	//给head的成员变量赋值
	head->id = -1;
	head->next = NULL;

	Node* pCur = head;
	Node* pNew = NULL;

	int data;
	while (1)
	{
		printf("请输入数据:");
		scanf_s("%d", &data);
		if (data == -1)
		{
			break;
		}
		pNew = (Node*)malloc(sizeof(Node));//新结点动态分配空间
		if (pNew == NULL)
		{
			continue;
		}
		//给pNew成员变量赋值
		pNew->id = data;
		pNew->next = NULL;

        //链表建立关系
		 
		//当前结点的next指向pNew
		pCur->next = pNew;

		//pNew下一个结点指向NULL
		pNew->next = NULL;

		//把pCur移动到pNew,pCur指向pNew
		pCur = pNew;
	}
	return head;
}

//链表的遍历
int SListPrint(Node* head)
{
	if (head == NULL)
	{
		return -1;
	}
	//取出第一个有效结点(头结点的next)
	Node* pCur = head->next;
	printf("head-> ");
	while (pCur != NULL)
	{
		printf("%d-> ", pCur->id);

		//当前结点往下移动一位,pCur指向下一个
		pCur = pCur->next;
	}
	printf("NULL\n");
	return 0;
}
//在值为x的结点前,插入值为y的结点;若值为x的结点不存在,则插在表尾
int SListNodeInsert(Node* head, int x, int y)
{
	if (head == NULL)
	{
		return -1;
	}
	Node* pPre = head;
	Node* pCur = head->next;
	while (pCur != NULL)
	{
		if (pCur->id == x)
		{
			break;
		}

		//pPre指向pCur位置
		pPre = pCur;
		pCur = pCur->next;//pCur指向下一个结点

	}
	//2种情况
	//1.找到匹配的结点,pCur为匹配结点,pPre为pCur上一个结点
	//2.没有找到匹配结点,pCur为空节点,pPre为最后一个结点

	//给新结点动态分配空间
	Node* pNew = (Node*)malloc(sizeof(Node));
	if (pNew == NULL)
	{
		return -2;
	}
	//给pNew的成员变量赋值
	pNew->id = y;
	pNew->next = NULL;
	//插入指定位置
	pPre->next = pNew;
	pNew->next = pCur;
	return 0;
}
int SListNodeDel(Node* head, int x)
{
	if (head == NULL)
	{
		return -1;
	}
	Node* pPre = head;
	Node* pCur = head->next;
	int flag = 0;//0没有找,1代表找到了
	while (pCur != NULL)
	{
		if (pCur->id == x)
		{
			pPre->next = pCur->next;//pPre的下一个指向pCur的下一个
			free(pCur);
			pCur = NULL;
			flag = 1;
			break;
		}
		pPre = pCur;
		pCur = pCur->next;
	}
	if (flag == 0)
	{
		printf("没有值为%d的结点", x);
		return -2;
	}
}
int SListNodeDestroy(Node* head)//清空链表,释放所有结点
{
	if (head == NULL)
	{
		return -1;
	}
	Node* tmp = NULL;
	int i = 0;
	while (head != NULL)
	{
		//保存下一个结点
		tmp = head->next;
		free(head);
		head = NULL;

		//head指向tmp
		head = tmp;
		i++;
	}
	printf("i=%d\n", i);
	return 0;
}
int main()
{
	Node* head = NULL;
	head = SListCreat();
	SListPrint(head);

	SListNodeInsert(head, 5, 4);
	printf("在5的前面插入4后\n");
	SListPrint(head);

	SListNodeDel(head, 5);
	printf("删除5结点之后\n");
	SListPrint(head);

	SListNodeDestroy(head);
	head = NULL;
	printf("\n");
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写不出bug的小李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值