C语言实现数据结构单链表(头插法)

本文详细介绍了一个使用C语言实现的链表的各种基本操作,包括创建、显示、判断空表、获取长度、查找元素、插入元素、删除元素及销毁链表等,并提供了完整的代码示例。
#include <stdio.h>
#include <malloc.h>

 typedef struct LNode
 {
	int data;
	struct LNode *next;			//指向后继元素; 
 } LinkNode;
 
 void CreateList(LinkNode *&L,int a[],int n)
 {
 	LinkNode *s;
 	L = (LinkNode*)malloc(sizeof(LinkNode));
 	L->next = NULL;
	//为了实现头插法与现实的数组排列顺序相同,这里将for循环从大到小,实现顺序调换 
	for(int i=n-1; i>=0; i--) 
	{
		s = (LinkNode*)malloc(sizeof(LinkNode));
		s->data = a[i];
		s->next	= L->next;
		L->next = s;
	} 
 }
 
 void DispList(LinkNode *L)
 {	
 	LinkNode *p = L;
 	printf("顺序表为:(");
	while(p->next != NULL)
	{	
		p = p->next;
		if(p->next!=NULL)
		{
			printf("%d,",p->data);
		}
		else
		{
			printf("%d",p->data);	
		}
	}	
	printf(")\n");
 }
 
 bool ListEmpty(LinkNode *L)
 {
 	if(L->next!=NULL)
 	{
 		printf("此表不为空表\n");
	 }
	 else
 	{
 		printf("此表为空表\n");
	 }
 }
 
 int ListLength(LinkNode *L)
 {
 	int len = 0;
 	LinkNode *p = L;
 	while(p->next != NULL)
 	{
 		p = p->next;
 		len++;
	 }
 	printf("当前的链表长度为:%d\n\n",len);
  } 
 
 int GetElem(LinkNode *L,int a,int &e)
 {
 	int n=1;
 	LinkNode *p = L->next;
 	while(n<a && p!=NULL)		//p!=NULL很重要,p=NULL意思是指针p为空,不存在data和next,
	{ 							//因此如果不加这句后面的p=p->next本身就不存在了,就会出错 
 		n++;
 		p = p->next;
	}
	
	if(a<=0 || p == NULL)
	{
		printf("超出搜索范围\n\n");
	}
	else
	{
		e = p->data;
		printf("该链表位于第%d位置的元素为:%d\n\n",a,e); 
	}
 }
 
 
 int LocateElem(LinkNode *L,int a,int &e)
 {
 	int n=0;
 	LinkNode *p = L;
 	while(p != NULL && p->data!=a)			//这里要注意&&是短路与,因此p!=NULL应该要先放前面,否则报错 
 	{
 		p=p->next;
 		n++;
	}
	if(p == NULL)
	{
		printf("该链表不存在这一元素\n\n");
	}
	else
	{
		e = n;
		printf("该元素在链表的位置为:%d\n\n",e);
	}
 }

bool ListInsert(LinkNode *L,int a,int c)
{
	LinkNode *s,*p=L;
	int i = 1;
	while(i<a && p!=NULL)
	{
		i++;
		p = p->next;
	}
	if(a<=0||p==NULL)
	{
		printf("超出插入范围\n");
	}
	else
	{
		s = (LinkNode *)malloc(sizeof(LinkNode));
		s->data = c;
		s->next = p->next;
		p->next = s;
	 }
	 DispList(L);
	 ListLength(L);
}
 
 bool ListDelete(LinkNode *L,int a)
{
	LinkNode *q,*p=L;
	int i = 0,e;
	while(i<a-1 && p!=NULL)
	{
		i++;
		p = p->next;
	}
	if(a<=0 || p==NULL)
	{
		printf("超出删除范围\n");
	}
	else
	{
		q = p->next;
		if(q==NULL)
		{
			return(printf("超出删除范围\n\n"));
		}
		e = q->data;
		p->next = q->next;
		free(q);
		printf("被删除的元素为%d\n",e);
	 }
	 DispList(L);
	 ListLength(L);
}
  
 void DestroyList(LinkNode *L)
 {
 	LinkNode *pre=L,*p=L->next;
 	while(p!=NULL)
 	{
 		free(pre);
 		pre = p;
 		p = pre->next;
	}
 	free(pre);
 	ListLength(L);
 	printf("销毁成功"); 
 }
 
 int main()
 {
 	LinkNode *L;
 	
 	int m; 
	printf("请输入要创建的数组元素个数:");
	scanf("%d",&m);
	int u[m];
	
	for(int i=0; i<m; i++)
	{	
		int h;
		printf("请输入第%d个元素的值:",i+1);
		scanf("%d",&h);
		u[i] = h;
	}
 	
 	CreateList(L,u,m);
 	DispList(L);
 	ListEmpty(L);
 	ListLength(L);
 	
 	int a,e;
 	printf("请输入要搜索的元素位置:");
	scanf("%d",&a);
 	GetElem(L,a,e);
 	
 	int b,e_1;
 	printf("请输入要定位的元素:");
	scanf("%d",&b);
 	LocateElem(L,b,e_1);
 	
 	int c,d;
 	printf("请输入要插入的元素:");
	scanf("%d",&c);
	printf("请输入要插入的元素位置:");
	scanf("%d",&d);
 	ListInsert(L,d,c);
 	
 	int i;
	printf("请输入要删除的元素位置:");
	scanf("%d",&i);
	getchar();
 	ListDelete(L,i);
 	
 	char C;
 	printf("是否要置空该链表(是/C)?\n");
	scanf("%c",&C);
	if(C =='C')
	{
		DestroyList(L);
	}
 	
 }
               

运行结果

在这里插入图片描述

在C语言中,循环单链表是一种特殊的线性数据结构,在这种结构里每个节点都包含两个部分:一个是存储的数据元素;另一个是指向下一个节点的指针。对于循环单链表而言,它的最后一个节点指向第一个节点形成闭环。 下面将介绍如何通过“头插法”创建并操作这样的列表: ### 定义结点 ```c typedef struct Node { int data; struct Node* next; // 指向前驱节点(即下一个节点) } Node; ``` ### 创建新节点函数 我们先编写一个辅助函数用于生成新的节点实例,并初始化其`data`成员变量以及设置next为NULL表示此节点当前无后续节点连接. ```c Node* create_node(int value) { Node *new = (Node*)malloc(sizeof(Node)); if (!new) return NULL; new->data = value; new->next = NULL; return new; } ``` ### 头实现 接下来就是重点——采用"头插法"构建循环单链表了。“头插法”的特点在于每次新增加一个元素都会成为新的首项位置处的新头部元素,而原本就存在的旧头会被移动到第二个位置上依次类推下去。 下面是具体的代码实现: ```c void insert_at_head_circular_ll(Node** head_ref, int newData) { /* 1. 创建一个新的节点 */ Node* newNode = create_node(newData); /* 2. 如果list为空,则让该节点自成环路 */ if (*head_ref == NULL) { newNode->next = newNode; *head_ref = newNode; return; } else { /* 获取原来的head节点 */ Node* currentHead = *head_ref; /* 找到最后一个节点(即前导至自身形成的那个封闭圈)*/ while(currentHead->next != *head_ref){ currentHead = currentHead->next; } /* 更新最后节点的next指向新建node*/ currentHead->next = newNode; /* 新建node 的 next 应当指向之前的头节点 */ newNode->next = *head_ref; /* 最后更新链表的头引用为新加入的那个节点 */ *head_ref = newNode; } } ``` 上述过程首先检查是否有现存的第一个节点存在(`if(*head_ref==NULL)`),如果不存在则直接建立一个闭合的单节点环形链条作为初始状态;若有既定内容,则遍历直到找到现有尾端再将其链接回最新添加进来的头部即可完成整个入流程. ### 示例测试 这里提供一段简单的主程序帮助理解以上所描述的操作步骤. ```c int main(){ Node* list = NULL; insert_at_head_circular_ll(&list ,4); insert_at_head_circular_ll(&list ,5); insert_at_head_circular_ll(&list ,6); printList(list); return 0; } // 输出所有节点值的辅助打印功能 void printList(Node *n){ printf("Circular Linked List is:\n"); do{ printf("%d ", n->data); n=n->next; }while(n!=list); printf("\n"); } ``` 请注意这段示例仅演示了基本的概念和方,实际应用时需要考虑更多边界条件如内存管理等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值