C语言实现链表

链表是数据结构最为基础的一种 学习之后想要自己实现一下 所以就开了一个长期更新的博客 记录自己实现各种数据结构的帖子 都是一些比较基础的

链表由一系列不必在内存中连续的结构组成。每一个结构都含有表元素和指向包含该元素的后继元的结构的指针,我们称之为Netx指针,最后一个单元的Next指针指向NULL,即指向空;因此就有以下定义的结构体表示的链表节点:

/*定义线性链表的结构*/
typedef struct LNode
{
	int date;	//数据域
	struct LNode *next;	//指向下一个节点的指针,即指针域
}LNode;

有了节点之后,我们就需要创建一个链表,因此用以下函数来创建一个带有头结点的链表(该创建方法被称为尾插法)C语言实现链表_第1张图片

LNode* CreateList(int n)
{
	LNode* s;
	LNode* r;	//分别创建用来指向新节点(s)和尾节点(r)的指针
	/*我认为这里是对节点L的重复初始化,但是在主函数中不对节点L进行初始化会报错 L未被初始化*/
	LNode *L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	r = L;
	for (int i = 0; i < n; i++)
	{
		s = (LNode*)malloc(sizeof(LNode));	//为新节点申请内存空间
		printf("输入数据:");
		scanf("%d", &s->date);
		r->next = s;	//将新节点“连接”在尾节点之后
		r = s;	//新节点变为尾节点
	}
	if(L->next != NULL)
		r->next = NULL;	//将尾节点的指针域置位空
	return L;
}

成功创建了一个链表之后,相信很多人都想看看链表所保存的数据是不是自己所输入的数据,因此,我们就用一个遍历链表的函数将数据全部输出,并检查是否和自己所输入的数据相符合:

//遍历链表,输出数据
void OutputLinkList(LNode *L)
{
	LNode* temp = L;	//使用临时变量temp暂存头结点的值 防止遍历链表时头结点移动到尾节点导致链表丢失
	while (temp->next != NULL)
	{
		//由于链表含有头结点 所以应该从链表的第二个节点开始输出并且依次后移
		temp = temp->next;
		printf("%d ", temp->date);
		printf("\n");
	}
}

注意,由于这是带有头结点的链表,所以应该从链表的第二个节点输出,上述代码已经说明,就会不赘述了

判断链表是否为空

//判断是否为空链表
void IsEmpty(LNode *L)
{
	/*判断是否为空列表只需要判断头结点的指针域是否置空,若置空则为空链表,反之则为非空链表*/
	if (L->next == NULL)
		printf("空链表!");
	else printf("非空链表!");
}

有了链表,我们当然就需要获取链表中指定位置的元素

//定位获取链表中某一个元素 参数position是指定的位置
int GetNode(LNode *L, int *n, int position)
{
	LNode *P = L;	//创建临时变量并赋值为头结点 以免后移时丢失头结点位置
	int j = 0;	//计数器 由于这是带有头结点的链表 头结点中的数据域数据位空 所以计数器从0开始
	while ((P != NULL) && (j <= position))
	{
		//指针后移 查找指定元素
		P = P->next;
		++j;
	}
	//未查找到指定元素的条件
	if ((P == NULL) || (j > position))
		return false;
	else
	{
		*n = P->date;
		return true;
	}
}

其中,应该注意区分获取指定元素和指定位置元素的区别,获取指定位置的元素指的是链表中第几个元素。
程序员的工作被称为增删改查,上面有了对链表的查,接下来介绍对链表的增·删·改
向链表中增加节点,也被称作向链表中插入节点:

//插入新节点到链表中指定的位置
LNode* InsertNode(LNode *L)
{
	LNode *P = L;
	int j = 0;	//计数器 由于有数据域为空的头结点所以从0开始
	int inser_position;	//新节点将插入到position之前
	printf("插入到链表中的位置:");
	scanf("%d", &inser_position);
	//定位第inset_position-1个节点的位置
	while ((P != NULL) && (j < inser_position - 1))
	{
		P = P->next;
		++j;
	}
	LNode *new_node = (LNode*)malloc(sizeof(LNode));	//为新插入的节点申请内存空间
	printf("输入节点的值:");
	scanf("%d", &new_node->date);
	new_node->next = P->next;
	P->next = new_node;
	return L;
}

C语言实现链表_第2张图片
由于链表在内存中的不连续性,所以要先将新节点和第position个节点链接起来,然后再讲第position-1个节点和新节点链接起来

链表节点的删除:

//删除链表中指定位置的节点
LNode* DeleteNode(LNode *L)
{
	int j = 0;	//计数器
	LNode *P = L;
	int delete_position;	//删除节点的位置
	printf("输入需要删除节点的位置:");
	scanf("%d", &delete_position);
	//寻找第delete_position - 1个节点的地址并保存在 P 中
	while ((P->next != NULL) && j < delete_position - 1)
	{
		P = P->next;
		++j;
	}
	if ((P->next == NULL) && (j > delete_position - 1))
	{
		printf("输入的位置非法,程序退出!\n");
		return L;
	}
	LNode *Q = P->next;	//记录第delete_position节点的地址
	P->next = Q->next;	//删除指定的节点
	free(Q);	//	释放指定节点的内存空间
	return L;
}

链表节点数据域的值改动过于简单就不做叙述,至此链表基本的增删改查全部介绍完。

你可能感兴趣的:(C语言实现数据结构)