【数据结构】之线性表(链式存储结构)

本文深入讲解链表数据结构,包括头插法与尾插法创建链表,以及如何进行结点的插入、删除操作。通过代码示例,帮助读者理解链表的工作原理和常见操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主威威喵  |  博客主页https://blog.youkuaiyun.com/smile_running

    链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表的数据结构包含两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。如下图所示:

    如图中,Data 保存的就是数据域,地址保存的就是指针域,它指向的是下一个结点。用代码的方式表示呢,它的数据结构类型为这样的:

typedef struct Node
{
	int data; // 数据域
	struct Node *next; // 指针域,指向下一个节点
}LinkList;

    使用链式结构的好处就是无需知道其数据的大小,比如顺序结构需要预先知道数据大小,这是它的一个优点。链式结构可以充分利用计算机内存空间,实现灵活的内存动态管理。那么如何初始化一个链表呢?

一、头插法

    初始化链表的方式有两种:一种是头插法,另一种是尾插法。顾名思义,头插法就是将新来的数据添加到已存在的结点之前,比如以下的图例:

此时,链表的输出结果与插入时的结果正好是倒序的,以下是头插法的实现代码:

/** 建立链表 - 头插法**/
LinkList *CreateHead(int length)
{
	int i=0;
	LinkList *head, *node, *end; // 头节点、中间节点、尾节点
	head = (LinkList *)malloc(sizeof(LinkList));
	head->data = length; // 头节点数据保存链表的长度
	head->next = NULL;
	end = head;

	while(i<length)
	{
		node = (LinkList *)malloc(sizeof(LinkList));
		printf("插入整数: \n");
		scanf("%d", &node->data);
		node->next = end;
		end = node;

		i++;
	}
	return end;
}

头插法是将输入的值插到已经存在的结点之前,所以头插法的输出结果是倒序的,如下:

二、尾插法

   对于头插法,做一个简单的了解即可,因为我们在实际中插入的顺序和输出的顺序一般都是一致的,否则看着也非常别扭。下面来看看尾插法的做法吧。尾插法其实就是将新的数据插入到已经存在的结点之后,保证了插入时的顺序,如下图:

 尾插法的关键代码如下:

/** 建立链表 - 尾插法**/
LinkList *CreateStern(int length)
{
	int i=0;
	LinkList *head, *node, *end; // 头节点、中间节点、尾节点
	head = (LinkList *)malloc(sizeof(LinkList));
	head->data = length; // 头节点数据保存链表的长度
	end = head;

	while(i<length)
	{
		node = (LinkList *)malloc(sizeof(LinkList));
		printf("插入整数: \n");
		scanf("%d", &node->data);
		end->next = node;
		end = node;

		i++;
	}
	end->next = NULL;
	//返回头节点指针
	return head;
}

    接着,我们来看看如何向一个已经存在的链表中插入新的结点。其做法是:定义一个 node 结点,保存所插入的值,然后 node 的指针域保存的是 L>next 结点。L>next 结点的指针域就不再是之前的了,而是刚刚插入的最新的 node 结点,如下图所示:

其插入结点的代码如下:

/** 向链表中插入元素 **/
Status Insert(LinkList *list, int data, int pos)
{
	int index = 1;
	LinkList *node;	

	if(pos<1 || pos>Length(list)+1)
	{
		printf("下标异常!\n");
		return ERROR;
	}

	node = (LinkList *)malloc(sizeof(LinkList));
	list->data++;// 表长 + 1

	while(index<pos && list!=NULL)
	{
		list = list->next;
		index++;		
	}
	
	node->data = data;	
	node->next = list->next;
	list->next = node;

	printf("插入元素:%d 成功!\n", data);
	return OK;
}

删除就比较简单了,把 L->next 指针域指向 L->next->next 即可,如下图:

其代码如下:

/** 删除链表中的元素 **/
Status Delete(LinkList *list, int pos)
{
	int index = 1;
	LinkList *node;	

	if(pos<1 || pos>Length(list)+1)
	{
		printf("下标异常!\n");
		return ERROR;
	}

	list->data--; // 表长 -1

	while(index<pos && list!=NULL)
	{
		list = list->next;
		index++;
	}

	node = list->next;
	list->next = node->next;

	printf("删除元素成功!\n");
	return OK;
}

下面是尾插法构建一个链表的完整代码,包括插入和删除结点、打印结点、获取链表的长度等操作。代码如下:

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

#define OK 1
#define ERROR 2
typedef int Status;

typedef struct Node
{
	int data; // 数据域
	struct Node *next; // 指针域,指向下一个节点
}LinkList;

/** 建立链表 - 尾插法**/
LinkList *CreateStern(int length)
{
	int i=0;
	LinkList *head, *node, *end; // 头节点、中间节点、尾节点
	head = (LinkList *)malloc(sizeof(LinkList));
	head->data = length; // 头节点数据保存链表的长度
	end = head;

	while(i<length)
	{
		node = (LinkList *)malloc(sizeof(LinkList));
		printf("插入整数: \n");
		scanf("%d", &node->data);
		end->next = node;
		end = node;

		i++;
	}
	end->next = NULL;
	//返回头节点指针
	return head;
}

/** 向链表中插入元素 **/
Status Insert(LinkList *list, int data, int pos)
{
	int index = 1;
	LinkList *node;	

	if(pos<1 || pos>Length(list)+1)
	{
		printf("下标异常!\n");
		return ERROR;
	}

	node = (LinkList *)malloc(sizeof(LinkList));
	list->data++;// 表长 + 1

	while(index<pos && list!=NULL)
	{
		list = list->next;
		index++;		
	}
	
	node->data = data;	
	node->next = list->next;
	list->next = node;

	printf("插入元素:%d 成功!\n", data);
	return OK;
}


/** 删除链表中的元素 **/
Status Delete(LinkList *list, int pos)
{
	int index = 1;
	LinkList *node;	

	if(pos<1 || pos>Length(list)+1)
	{
		printf("下标异常!\n");
		return ERROR;
	}

	list->data--; // 表长 -1

	while(index<pos && list!=NULL)
	{
		list = list->next;
		index++;
	}

	node = list->next;
	list->next = node->next;

	printf("删除元素成功!\n");
	return OK;
}

/** 摧毁链表 **/
void Destory(LinkList *list)
{
	LinkList *head;
	while(head!=NULL)
	{
		head = list->next;
		free(list);
		list = head;
	}
}

/** 打印链表 **/
void Print(LinkList *list)
{
	printf("链表:");
	while(list->next != NULL)
	{
		list = list->next;
		printf("%d ", list->data);
	}
	printf("\n");
}

/** 获取链表的长度 **/
int Length(LinkList *list)
{
	// 返回头节点的数据域
	return list->data;
}

void main()
{
	LinkList *list;

	int len;

	printf("请输入链表元素个数:");
	scanf("%d", &len);
	list = CreateStern(len);// 初始化链表

	Print(list);// 打印链表
	printf("链表长度:%d \n", Length(list));

	Insert(list, 45, 5);// 插入元素
	Print(list);// 打印链表
	printf("链表长度:%d \n", Length(list));

	Delete(list, 1);
	Print(list);// 打印链表
	printf("链表长度:%d \n", Length(list));

	Destory(list);
	printf("链表长度:%d \n", Length(list));
}

其运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值