【数据结构】C语言实现链表操作

        线性表是一种常用的简单数据结构,它是由零个或多个元素组成的有限序列。强调了元素的有限性和元素之间的顺序性

        线性表有两种物理结构,第一种是顺序存储结构,例如我们熟悉的数组。


线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。

        顺序结构最大的特点就是:顺序存储,随机访问 。对于初学者来说使用非常便利。但是,它致命的缺点在于:

1.相邻的两元素的存储位置(地址)也具有邻居关系,导致进行插入、删除等操作时需要移动大量元素,耗费时间。

2. 使用前需声明数组的长度,开辟固定的空间,且后续不能再修改。

3.只能存储一种类型的数据,内容单一,无法满足实际应用。

        于是我们引入了线性表的另一种物理结构:链式存储结构。

        链式存储结构的特点是用一组任意的存储单元来存储线性表的数据元素,不要求它们的地址相连,需要的时候就开辟新的空间。

        位置都不连在一起,我怎么找数据?

        在链式结构中,除了要存数据元素信息外,还要存储它后继元素的存储地址!它的特点与顺序结构相反:随机存储,顺序访问。

        链表可以动态地进行存储分配,也正是因为这个特点,它具有强大功能,能够实现许多操作,例如:链表的创建、修改、查找、增加、删除、清空、输出......

        链表的结构特点:

  1. 基于结构体指针。
  2. 具有头节点(head),一般没有数据域,仅有指针域。
  3. 所有节点离散分布,仅由指针相联系。
  4. 头节点只有后继节点,尾节点只有前驱节点。

准备工作

(原创不易,希望各位看官不要吝啬手指,点点赞吧🌹)

引用头文件

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

定义结构体 

//一个简单结构体,只存一个数 
typedef struct Node
{
	int data;
	struct Node *next;
}linklist;

malloc函数

使用形式:

指针自身 = (指针类型*)malloc(sizeof(指针类型))

注意事项:
malloc函数的返回的是无类型指针,在使用时一定要强制转换为所需要的类型。
重点:

在使用malloc开辟空间时,使用完成一定要释放空间,如果不释放会造内存泄漏。
在使用malloc函数开辟的空间中,不要进行指针的移动,因为一旦移动之后可能出现申请的空间和释放空间大小的不匹配。


头插法创建链表 

头插法顾名思义,就是把新建的单元插在链表头部,这样形成的链表数据是反着存入的。

linklist *create_head(int n)
{
	linklist *head,*pt;
	head=(linklist *)malloc(sizeof(linklist));
    //注意初始化为NULL,以免造成内存泄漏。
	head->next=NULL;
	for(int i=1;i<=n;i++)
	{
		pt=(linklist*)malloc(sizeof(linklist));
		scanf("%d",&pt->data);
        //head的后继交给pt,成为pt的后继
        //pt又成为head的后继
		pt->next=head->next;
		head->next=pt; 
	}
	return head;
}
pt->next=head->next;
head->next=pt;

如图所示:

 尾插法创建链表 

linklist *create_tail(int n)
{
    //尾插法需要用到一个tail指针,一直跟随在链表尾部
	linklist *head,*tail,*pt;
	head=(linklist *)malloc(sizeof(linklist)); 
    //最开始头即是尾
	tail=head;
	for(int i=1;i<=n;i++)
	{
		pt=(linklist*)malloc(sizeof(linklist));
		scanf("%d",&pt->data);
		pt->next=NULL;
        //把pt接在尾部,然后tail后移
		tail->next=pt;
		tail=pt;
	}
	return head;
}
tail->next=pt;
tail=pt;

如图所示:


创建好链表以后,我们进行一些基本操作:

·检查链表是否为空

int judgeempty(linklist *head)
{
	if(head->next==NULL)
	{
		printf("The Linklist is empty.\n");
		return 0;
	}
	else
	{
		printf("The Linklist has something in it.\n");
		return 1;
	}
 } 

·求链表长度

void list_length(linklist *head)
{
	linklist *p;
	int cnt=0;
	p=head->next;
	while(p!=NULL)
	{
		cnt++;
		p=p->next;
	}
    head->data=cnt;//将长度存在头结点的数据域
    cout<<"链表长度为:"<<cnt<<endl;
	return ;
} 

·输出链表

void output(linklist *head)
{
	linklist *p;
	p=head->next;
	printf("H");
	while(p!=NULL)
	{
		printf("-->%d",p->data);
		p=p->next;
	}
	printf("\n");
}

求长度和输出的思路很简单,就是将创建好的链表遍历一遍。


查找链表元素

接着我们实现查找功能

1.输入位置,查找对应元素。

int get_it(linklist *head,int i,int *num)
{
	int cnt=1;
	linklist *temp;
	temp=head->next;
	while(temp&&cnt<i)
	{
		temp=temp->next;
		cnt++;
	}
	if(!temp||cnt>i)
	{
		return 0;
	}
	*num=temp->data;
	return 1;	
} 

2.输入元素,查找对应位置。

int search_it(linklist *head,int i,int *n)
{
	linklist *now=head->next;
	int index=1;
	while(now!=NULL)
	{
		if(i==now->data)
		{
			*n=index;
			return 1;
		}
		now=now->next;
		index++; 
	}
	return 0;
} 

修改、插入、删除操作

1.修改

int a;
printf("修改\n");
printf("输入你想要修改的位置 ");
scanf("%d",&a); 
HEAD=change_it(HEAD,a);
output(HEAD);
linklist *change_it(linklist *head,int n)
{
	linklist *t=head->next;
	int i=1;
	while(i<n&&t!=NULL)
	{
		t=t->next;
		i++;
	}
	if(t!=NULL)
	{
		printf("Input the value you want: ");
		scanf("%d",&t->data);
		printf("Change,Done!\n");
		return head; 
	}
	else
		printf("The node does not exist.\n");
	return head;
} 

2.插入

int b;
printf("插入\n");
printf("输入你想要插入的位置 ");
scanf("%d",&b); 
HEAD=insert_it(HEAD,b);
output(HEAD);
linklist *insert_it(linklist *head,int n)
{
	linklist *t=head;
	linklist *ip;
	int i=1;
	while(i<n&&t!=NULL)
	{
		t=t->next;
		i++;
	}
	if(t!=NULL)
	{
		ip=(linklist*)malloc(sizeof(linklist));
		printf("Input the value you want: ");
		scanf("%d",&ip->data);
		ip->next=t->next;
		t->next=ip;
		printf("Insert,Done!\n");
		return head; 
	}
	else
		printf("The node does not exist.\n");
	return head; 
} 

3.删除

int c;
printf("删除\n");
printf("输入你想要删除的位置 ");
scanf("%d",&c); 
HEAD=delete_it(HEAD,c);
output(HEAD);
linklist *delete_it(linklist *head,int n)
{
	linklist *t=head->next;
	linklist *dp;
	int i=1;
	while(i<n&&t!=NULL)
	{
		dp=t;
		t=t->next;
		i++;
	}
	if(t!=NULL)
	{
		dp->next=t->next;
		free(t);
        t=NULL;
		printf("Delete,Done!\n");
		return head; 
	}
	else
		printf("The node does not exist.\n");
	return head; 
} 

完成了上述的一系列操作,我们要具备环保意识,回收内存!

清空链表

void clearlist(linklist *head)
{
	linklist *q,*qr;
	q=head->next;
	while(q!=NULL)
	{
		qr=q->next;
		free(q);
		q=qr;
	} 
	head->next=NULL;
    q=NULL;
    qr=NULL;
	if(q==NULL)
		printf("CLEAR!");
	return ;
}

最后献上完整的主函数

int main()
{
	int n;
	scanf("%d",&n);
	linklist *HEAD;
	//创建链表 
	printf("创建链表\n");
    //HEAD=create_head(n);
	HEAD=create_tail(n);
	printf("\n"); 
	//检查、求长度、输出 
	printf("检查、求长度、输出链表\n");
	if(judgeempty(HEAD))
	{
		printf("%d\n",list_length(HEAD));
		output(HEAD);
	}
	printf("\n");
	//查找数据
	printf("查找下标对应数\n");
	int num;
	int *place;
	scanf("%d",&num);
	if(get_it(HEAD,num,place))
	{
		printf("The number with index %d is %d.\n",num,*place);
	}
	else
		printf("ERROR!\n"); 
	printf("\n");
	//查找下标
	printf("查找数对应下标\n");
	int *index;
	int element;
	scanf("%d",&element);
	if(search_it(HEAD,element,index))
	{
		printf("Congratulations!The index of %d is %d.\n",element,*index);
	}
	else
	{
		printf("Sorry!%d can't be found!\n",element);
	}
	printf("\n");
	
	//修改、插入、删除 
	int a,b,c;
	printf("修改\n");
    printf("输入你想要修改的位置 ");
	scanf("%d",&a); 
	HEAD=change_it(HEAD,a);
	output(HEAD);
	
	printf("插入\n");
	printf("输入你想要插入的位置 ");
	scanf("%d",&b); 
	HEAD=insert_it(HEAD,b);
	output(HEAD);
	
	printf("删除\n");
	printf("输入你想要删除的位置 ");
	scanf("%d",&c); 
	HEAD=delete_it(HEAD,c);
	output(HEAD);
	printf("\n"); 
	//清空 
	clearlist(HEAD);
	return 0;
} 

  • 13
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在C语言中,链表函数的实参“equal”通常是一个函数指针,用于比较链表中的节点值是否相等。 例如,以下是一个简单的链表结构体: ```c typedef struct node { int data; struct node *next; } Node; ``` 如果我们要在链表中查找特定的值,可以使用以下函数: ```c Node* find(Node *head, int value, int (*equal)(int, int)) { Node *p = head; while (p != NULL) { if (equal(p->data, value)) { return p; } p = p->next; } return NULL; } ``` 这个函数接受三个参数:链表头节点指针、要查找的值、以及一个函数指针equal。函数指针equal指向一个比较函数,该函数接受两个int类型的参数,分别表示链表节点的值和要查找的值,返回一个int类型的值表示比较结果。如果equal返回0,则表示两个值不相等;否则表示相等。 例如,我们可以定义一个比较函数,比较两个int类型的值是否相等: ```c int compare(int a, int b) { return a == b; } ``` 然后我们可以调用find函数,在链表中查找特定的值: ```c Node *head = NULL; // 创建链表... Node *p = find(head, 42, compare); if (p != NULL) { printf("找到了节点,值为%d\n", p->data); } else { printf("没找到节点\n"); } ``` 在上面的代码中,我们通过调用find函数,在链表中查找值为42的节点。函数指针equal指向了compare函数,表示比较两个int类型的值是否相等。如果找到了节点,则输出节点的值;否则输出“没找到节点”。 ### 回答2: 在C语言中,链表是一种常用的数据结构,通过链接每个节点形成的数据集合。链表的每个节点包含两个属性:数据和指向下一个节点的指针。 实现链表相关函数时,我们经常需要比较节点的数据。而equal函数就是用来判断两个节点的数据是否相等的。 equal函数的实参通常需要传入要比较的两个节点,然后返回一个布尔值表明它们数据是否相等。 在实现equal函数时,我们可以按照以下步骤进行: 1. 首先,我们需要定义一个自定义的结构体表示链表节点,结构体内部可以包含存储数据的成员和指向下一个节点的指针成员。 2. 接下来,我们可以定义equal函数,函数的声明可能类似于`bool equal(Node* node1, Node* node2)`,其中`Node*`表示节点指针类型,`bool`表示返回值类型。 3. 在函数内部,我们可以通过访问节点指针中的数据成员来进行比较。比较的方式可以根据具体的需求来确定,比如可以使用"=="来判断两个节点的数据是否相等。 4. 最后,根据比较结果,我们可以返回一个布尔值。一般地,如果两个节点的数据相等,我们可以返回`true`;否则,返回`false`表示它们的数据不相等。 总结: 在链表相关函数实现中,equal函数用于比较两个节点的数据是否相等。我们可以通过比较节点的数据来确定返回值,以便于其他函数在链表操作过程中使用。 ### 回答3: 在C语言链表函数中,如果我们想要判断两个链表是否相等,可以使用equal函数作为实参。 equal函数的功能是判断两个链表是否拥有相同的数据和结构。 在equal函数的编写过程中,我们可以使用循环逐个比较两个链表中的节点数据。首先,我们需要判断两个链表的节点数目是否相等,如果不相等则两个链表必定不相等。接下来,我们可以使用一个循环来迭代比较两个链表中对应位置的节点数据。如果在某一位置上两个节点的数据不相等,则可以判定链表不相等。如果循环结束后所有节点都相等,则可以判定链表相等。 实现equal函数时,可以将两个链表的头节点作为实参传递进来。函数的返回值可以设置为布尔类型,用于表示链表是否相等。在比较节点数据时,可以使用逻辑运算符进行判断,例如使用"=="来判断节点数据是否相等。 在函数代码编写完毕后,可以通过调用equal函数来比较两个链表是否相等。如果返回值为true,则表示两个链表相等;如果返回值为false,则表示两个链表不相等。 总之,equal函数作为实参用于判断两个链表是否相等,可以通过比较节点数据和结构来确定链表是否相等。函数的实现通常需要遍历链表,并使用逻辑运算符来进行比较判断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值