线性表是一种常用的简单数据结构,它是由零个或多个元素组成的有限序列。强调了元素的有限性和元素之间的顺序性。
线性表有两种物理结构,第一种是顺序存储结构,例如我们熟悉的数组。
顺序结构最大的特点就是:顺序存储,随机访问 。对于初学者来说使用非常便利。但是,它致命的缺点在于:
于是我们引入了线性表的另一种物理结构:链式存储结构。
链式存储结构的特点是用一组任意的存储单元来存储线性表的数据元素,不要求它们的地址相连,需要的时候就开辟新的空间。

位置都不连在一起,我怎么找数据?
在链式结构中,除了要存数据元素信息外,还要存储它后继元素的存储地址!它的特点与顺序结构相反:随机存储,顺序访问。
链表可以动态地进行存储分配,也正是因为这个特点,它具有强大功能,能够实现许多操作,例如:链表的创建、修改、查找、增加、删除、清空、输出......
链表的结构特点:
准备工作
(原创不易,希望各位看官不要吝啬手指,点点赞吧🌹)
引用头文件
#include <stdio.h>
#include <stdlib.h>
 
定义结构体
//一个简单结构体,只存一个数 
typedef struct Node
{
	int data;
	struct Node *next;
}linklist;
 
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;
	}
 }  
·求链表长度
int list_length(linklist *head)
{
	linklist *p;
	int cnt=0;
	p=head->next;
	while(p!=NULL)
	{
		cnt++;
		p=p->next;
	}
	return cnt;
}  
·输出链表
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,num;
	while(now!=NULL)
	{
		num=now->data ;
		if(num==i)
		{
			*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;
	int i=0;
	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;
	linklist *dp;
	int i=0;
	while(i<n&&t!=NULL)
	{
		dp=t;
		t=t->next;
		i++;
	}
	if(t!=NULL)
	{
		dp->next=t->next;
		free(t);
		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;
	while(q!=NULL)
	{
		qr=q->next;
		free(q);
		q=qr;
	} 
	head->next=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;
} 









