数据结构之单链表/创建/删除/插入详细解说(C语言)

前言:

最近在学习数据结构中的链表,可能是刚刚接触的吧,感觉有点难度,它结合了指针及结构体,所以,当你在看这篇博客时,你应该对C语言的指针及其结构体要有了解,不然的话,你会在看这篇博客时,会说,这个博主在写什么乱七八糟的东西啊,不知道怎么敢发。哈哈,我可不想听到大家对我说这样的话。鉴于此,我会将每一步讲的十分仔细的。

先来了解一下基础的知识吧。
图1
图2图3

好了,接下来实战。

1.1.定义相关的结构体

1.1.1.代码:

#define OK 1

#define ERROR 0

#define TURE 1

#define FALSE 0

#define MAXSIZE 20

typedef int Status;   //Status为函数的类型

typedef int ElemType;

typedef struct Node{

	ElemType data;
	struct Node *next;
};

typedef struct Node *LinkList;    //定义LinkList

1.2.单链表的读取

 在单链表中,由于第i个元素没办法一开始就知道,必须得从头开始找。因此,对于单链表实现第i个元素的数据的操作GetElem。
在读取第i个数据的算法思路:

  1. 申明一个结点指向链表的第一个结点。
  2. 定义一个j,当j<i时,让p的指针向后移动,不断指向下一结点。
  3. 定义一个数e,并将找到的第i个数据返回e。
  4. 如果查找不成功,则表明第i个数据不存在。

1.2.1.代码算法:

Status GetElem(LinkList L,int i,ElemType *e){

	int j=1;
	
	LinkList p     //申明一个结点
	
	p=L->next;      //让p指向第一个结点
	
	while(p&&j<i){
	
	    p=p->next;         //每次循环都将指向下一个结点,直到直到第i个结点

	    ++j;
	    
	}
	
	if(!p||j>i){
	
		return ERROR;
		
	}
	
	*e=p->data;      //用e的返回查找的数
	
	return OK;
	
}

 上述代码的算法就是遍历每一个元素,基本上和刚开始学的数组是差不多的,然而不同的是这里是用指针的指向去遍历元素,而数组是用索引去遍历元素。

1.3.单链表的插入

 在单链表里,我们就不必像数组那样将一些数组中的元素后移或者是前移,而是,将指针的指向要插入的元素,而插入的元素指针指向它前面元素在它未插入前指向的元素即可,所以,在这一方面链表显然更为灵活。

图4

1.3.1.代码算法:

//单链表L存在,i表示在在第i个数前面插入数为e的元素

Status ListInsert(LinkList *L,int i,ElemType e){

	int j=1;
	
	ListLink p,s;
	
	p=*L;
	
	while(p&&j<i){
	
		p=p->next;
		
		++j;
		
	}
	if(!p||j>i){
	
		return ORRER;
		
	}
	
	s=(LinkList)malloc(sizeof(Node));       //申请新的结点;
	
	s->data=e;
	
	s->next=p->next;
	
	p->next=s;
	
	return OK;
	
}

1.4.单链表的删除

 当然,对于单链表的删除,我们现在应该有一定的意识了吧,在这里,我们可以将要删除的元素的前一元素指向其的后一位元素,简单的说就是,指针在指向下一元素时,跳过要删除的元素。在这里,是不是为链表的灵活连连叫好。
图5

1.4.1代码算法:

Status ListDelete(LinkList *L,int i,ElemType *e){

	int j=1;
	
	LinkList p,q;
	
	p=*L;
	
	while(j<i&&p->next){    //这里判断的是p->next是因为要指向被删除元素的后一位元素,所以要判断它是否存在
	
		p=p->next;
		
		++j;
		
	}
	
	if(j>i||!(p->next)){
	
		return ORRER;
		
	}
	
	q=p-next;
	
	p->next=q->next;
	
	*e=q->data;
	
	free(q);      //回收此结点
	
	return OK;
	
}	

1.5.单链表的整表创建

 创建单链表的过程,其实就是动态创建一个链表的过程依次建立结点,并插入元素,在这里,我介绍两个方法插入元素,一个是头插法,一个是尾插法。对于,头插法,就是将每个插入的元素放在第一个结点,然后依次类推,当然,尾插法,就是将每个要插入的元素放在最后一个结点,以此类推。
头插法:
图6
尾插法:
图7

1.5.1.代码算法:

//头插法
 void CreateListHead(LinkList *L,int n){
 
 	LinkList p;
 	
 	int i;
 	
 	srand(time(0));
 	
 	*L=(LinkList)malloc(sizeof(Node));
 	
 	(*L)->next=NULL;        //建立一个带头结点链表
 	
 	for(i=0;i<n;i++){
 	
 		p=(LinkList)malloc(sizeof(Node));
 		
 		p->data=rand()%100+1;    //生成100以内的数字
 		
 		p->next=(*L)->next;
 		
 		(*L)->next=p;                          //插入到表头	
 		
	}
}
//尾插法
void CreateListTail(LinkList *L,int n){

	LinkList p,r;
	
	int i;
	
	srand(time(0));
	
	*L=(LinkList)malloc(sizeof(Node));

	r=*L;
	
	for(i=0;i<n;i++){
	
		p=(LinkList)malloc(sizeof(Node));
		
		p->data=rand()%100+1;
		
		r->next=p;
		
		r=p;
		
	}
	
	r->next=NULL;      //当前链表结束
}

想到整表的创建,那么肯定有整表的删除吧。

1.6.单链表的整表删除

 删除单链表是十分有用的,它可以腾出空间留给其他程序或软件的使用。
其算法思路是蛮简单的,就是一个一个的释放结点。

1.6.1.代码算法:

Status ClearList(LinkList *L){

	LinkList p.q;
	
	p=(*L)->next;
	
	while(p){
	
		q=p->next; 

		free(p);            //释放结点
		
		p=q;
		
	}
	
	(*L)->next=NULL;
	
	return OK;
	
}

上面我是分步给大家伪代码的,以方便大家能够理解,当然啦,接下来,我给出一些其在main()函数被调用时的用法,不过在调用其时,还要去定义一些函数,以便输出元素。

Status vis(ElemType e){

	printf("%d ",e);
	
	return OK;
} 

// 定义单链表长度的函数
int ListLength(LinkList L){

	int i=0;
	
	LinkList p=L->next;
	
	while(p){
	
		p=p->next;
		
		i++;
		
	}
	
	return i;
}
//定义一个将单链表中每个元素输出的函数
Status ListPrint(LinkList L){

	LinkList p=L->next;
	
	while(p){
	
		vis(p->data);
		
		p=p->next;
		
	}
	printf("\n");
	
	return OK;
}

2.1.主函数代码:

int main(){
	LinkList L;     //申明一个单链表
	
	ElemType e;      //元素的值
	
	Status i;          //相当于int i;
	
	int k,j;

	for(k=1;k<=10;k++){
	
		ListInsert(&L,1,k);
		
	}
	
	printf("插入后的链表为:");
	
	ListPrint(L);
	
	printf("单链表的长度为:%d\n",ListLenght(L));
	
	ClearList(&L);
	
	printf("清空后,其单链表的长度为:%d",ListLenght(L));
	
	for(j=1;j<=10;j++){
	
		ListInsert(&L,j,j);
		
	}
	
	printf("插入数据后,单链表为:");
	
	ListPrint(L);
	
	printf("单链表的长度为:%d\n",ListLength(L));
	
	GetElem(L,6,&e);
	
	printf("第6个元素为;%d\n");
	
	ListDelete(&L,3,&e);
	
	ListPrint(L);
	
	ClearList(&L);

	Create(ListHead(&L,20);
	
	printf("头插法创建单链表的元素为:");
	
	ListPrint(L);
	
	ClearList(&L);
	
	CreateListTail(&L,20);
	
	printf("尾插法创建单链表的元素为:");
	
	ListPrint(L);
	
	return 0;
	
}

好了,今天的博客就要在这里结束了,不过在下一个博客我还会介绍静态链表,循环链表的相关知识。不过呢,我也十分感谢CSDN上有些大牛的博客让我学会了单链表。最后,希望大家能够多多支持。😄😄😄

参考文献:

《大话数据结构》

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值