嵌入式学习Day14

一、单向链表(含逆置)

head.h

#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct node
{
	int date;
	struct node *next;
}node,*node_p;
node_p creat_lik_list();//创建头节点
node_p new_node(int date);//创建节点
void insert_head(node_p H,int date);//头插
int empty_lik(node_p H);//判空
void show_lik(node_p H);//输出
void delete_head_lik(node_p H);//头删
void insert_tail(node_p H,int date);//尾插
void delete_tail(node_p H);//尾删
void insert_pos(node_p H,int pos,int date);//按位置插入
void delete_pos(node_p H,int pos);//按位置删除
node_p search_pos(node_p H,int pos);//按位置查找
void update_value(node_p H,int key,int date);//按位置修改
void replce_pos_value(node_p H,int pos,int date);//按位置替换
void overturn_lik(node_p H);//逆置
#endif

main.c

int main()
{
node_p H=creat_lik_list();
insert_head(H,11);
insert_head(H,22);
insert_tail(H,33);
insert_tail(H,44);
insert_tail(H,55);
insert_head(H,66);
delete_head_lik(H);
delete_tail(H);
insert_pos(H,2,77);
delete_pos(H,3);
show_lik(H);
printf("search=%d\n",*search_pos(H,2)->next);
replce_pos_value(H,3,66);
update_value(H,44,45);
show_lik(H);
overturn_lik(H);
show_lik(H);
}

test.c

#include"head.h"
node_p creat_lik_list()//创建头节点,创建链表,头节不存储值
{
	node_p H =(node_p)malloc(sizeof(node));
	if(H==NULL)
	{
		printf("apply to fail!\n");
		return NULL;
	}
	H->next=NULL;//无节点指向空
	H->date=0;
	return H;
}
node_p new_node(int date)//创建节点,创建数据节点
{
	node_p new =(node_p)malloc(sizeof(node));//申请节点地址
	if(new==NULL)
	{
		printf("apply to fail!\n");
		return NULL;
	}
	new->date=date;//节点赋值
	return new;
}
void insert_head(node_p H,int date)
{
	if(H==NULL)
	{
		printf("init error!\n");
		return;
	}
	node_p new =new_node(date);//申请插入的值以及地址
	new->next=H->next;//将头地址(NULL)赋值给申请节点内指针做保存,作为收尾
	H->next=new;//将头节点内指针更新为申请的节点地址,把下一个节点的存储地址,放到上一个节点,更新头地址,前移
	H->date++;//记录长度
}
int empty_lik(node_p H)
{
	if(H==NULL)
	{
		printf("init error!\n");
		return -1;
	}
	return H->next==NULL?1:0;
}
void show_lik(node_p H)
{
	if(empty_lik(H))
	{
		printf("no input!\n");
		return;
	}
	node_p p=H;//头节点的next表示第一个节点指针,需输出
	while(p->next!=NULL)//链表节点最后一个的标志,参考头插逻辑
	{
	printf("%d->",p->next->date);
	p=p->next;//当前节点的*next给p,该*next实际是下一个节点存储的实际位置(指针),换言之,当下次取p时,便到了下一个节点上
	}
	printf("NULL\n");
}
void delete_head_lik(node_p H)//头删是删除头节点下面的一个节点,该节点的指针是在头节点里,所以要删除该地址,并将该节点所包含的下一个节点的指针与头连接
{
	if(empty_lik(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	node_p p=H->next;
	H->next=H->next->next;//H->next是头节所存的地址,该地址也是下一个节点结构体申请的存储地址(下个节点的指针),所以H->next->next表示下一个节点内的*next
	free(p);
	H->date--;
}
void insert_tail(node_p H,int date)
{
	if(H==NULL)
	{
		printf("init error!\n");
		return;
	}
	node_p p=H;
	while(p->next!=NULL)//找到最后的位置
	{
		p=p->next;	
	}
	node_p new=new_node(date);
	new->next=p->next;
	p->next=new;
	H->date++;
}
void delete_tail(node_p H)//删除最后一个元素,即倒数第二个节点存储的地址
{
	if(empty_lik(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	node_p p=H;
	while(p->next->next!=NULL)//前一个节点的next存放下一个节点申请的地址,再取next,便是下一个节点的next,换言之,判断下一个节点的地址
	{
		p=p->next;	
	}
	node_p del =p->next;
	p->next=p->next->next;
	free(del);
	H->date--;
}
void insert_pos(node_p H,int pos,int date)
{
	if(empty_lik(H))
	{
		printf("input empty!\n");
		return;
	}
	if(pos<=0||pos>H->date+1)
	{
		printf("input pos error!\n");
		return;
	}
	node_p new=new_node(date);
	node_p p=H;
	for(int i=0;i<pos-1;i++)//确定循环次数用for,确定pos-1位置,pos为实际位置
	{
		p=p->next;	
	}
	new->next=p->next;
	p->next=new;
	H->date++;
}
void delete_pos(node_p H,int pos)
{
	if(empty_lik(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	if(pos<=0||pos>H->date)
	{
		printf("input pos error!\n");
		return;
	}
	node_p p=H;
	for(int i=0;i<pos-1;i++)
	{
		p=p->next;
	}
	node_p del=p->next;
	p->next=p->next->next;
	free(del);
	H->date--;
}
node_p search_pos(node_p H,int pos)
{
	if(empty_lik(H))
	{
		printf("input empty,no find!\n");
		return NULL;
	}
	if(pos<=0||pos>H->date)
	{
		printf("input pos error!\n");
		return NULL;
	}
	node_p p=H;
	for(int i=0;i<pos-1;i++)
	{
		p=p->next;
	}
	return p;
}
void replce_pos_value(node_p H,int pos,int date)
{
	if(empty_lik(H))
	{
		printf("input empty,no find!\n");
		return;
	}
	if(pos<=0||pos>H->date)
	{
		printf("input pos error!\n");
		return;
	}
	node_p new =new_node(date);
	node_p p=search_pos(H,pos);
	//node_p del=p->next;
	//p->next=new;
	p->next->date=new->date;
	//new->next=del->next;//替换后,将该位置与后面连接
	//free(del);
}
void update_value(node_p H,int key,int date)
{
	if(empty_lik(H))
	{
		printf("input empty,no find!\n");
		return;
	}
	node_p p=H;
	node_p new=new_node(date);
	while(p->next!=NULL)
	{
		if(p->next->date==key)
		{
			p->next->date=new->date;
			return;
		}
		p=p->next;
	}
}
void overturn_lik(node_p H)
{
	if(empty_lik(H))
	{
		printf("input empty,don't overturn!\n");
		return;
	}
	if(H->next->next==NULL)//只有一个元素无需逆置
	{
		printf("only one,don't overturn!\n");
		return;
	}
	node_p p=H->next->next;//保存第二个点的地址,需要从第二个元素开始判断并且往前头插,需要一个原始元素作为参考,避免逆置的时候元素改变而引起整体改变
	H->next->next=NULL;//第一点的指针域置空,变为最后一个节点
	node_p q;
	while(p!=NULL)//p为刚开始保存的地址
	{
		q=p->next;//头插前保留下一个要头插的首地址,此处为原始保存的p地址开始
		p->next=H->next;//头插操作,不影响后面未进行头插的地址,从操作上看陆续向前逐一交换
		H->next=p;
		p=q;//指向下一个插入的节点,每进一次保存的位置后移一位
	}
}

运行结果:

二、单向循环链表

head.h

#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
	int date;
	struct node *next;
}node,*node_p;
node_p creat_loop_list();//创建头
node_p creat_node(int date);//创建点
int empty_loop(node_p H);//判空
void insert_head_loop(node_p H,int date);//头插
void show_loop(node_p H);//输出
void insert_tail_loop(node_p H,int date);//尾插
void delete_head(node_p H);//头删
void insert_pos(node_p H,int pos,int date);//按位置插入
node_p single_delete_head(node_p H);//删除头节点
void no_head_show(node_p T);//删除头节点输出
#endif

main.c

#include"head.h"
int main()
{
	node_p H=creat_loop_list();
	insert_head_loop(H,11);
	insert_tail_loop(H,22);
	insert_tail_loop(H,33);
	delete_head(H);
	insert_pos(H,3,44);
	show_loop(H);
	node_p T=single_delete_head(H);
//	H=NULL;
//	show_loop(H);运行报段错误
	no_head_show(T);
}

test.c

#include"head.h"
node_p creat_loop_list()
{
	node_p H=(node_p)malloc(sizeof(node));
	if(H==NULL)
	{
		printf("fail to apply!\n");
			return NULL;
	}
	H->date=0;
	H->next=H;
	return H;
}
node_p creat_node(int date)
{
	node_p new=(node_p)malloc(sizeof(node));
	if(new==NULL)
	{
		printf("fail to apply!\n");
		return NULL;
	}
	new->date=date;
	return new;
}
int empty_loop(node_p H)
{
	if(H==NULL)
	{
		printf("fail to apply!\n");
		return -1;
	}
	return H==NULL?1:0;
}
void insert_head_loop(node_p H,int date)
{
	if(H==NULL)
	{
		printf("init error!\n");
		return;
	}
	node_p new=creat_node(date);
	new->next=H->next;
	H->next=new;
	H->date++;
}
void show_loop(node_p H)
{
	if(empty_loop(H))
	{
		printf("input empty,don't output!\n");
		return;
	}
	node_p p=H;
	while(p->next!=H)
	{
		printf("%d->",p->next->date);
		p=p->next;
	}
	printf("H\n");
}
void insert_tail_loop(node_p H,int date)
{
	if(H==NULL)
	{
		printf("init error!\n");
		return;
	}
	node_p new=creat_node(date);
	node_p p=H;
	while(p->next!=H)
	{
		p=p->next;
	}
	new->next=p->next;
	p->next=new;
	H->date++;
}
void delete_head(node_p H)
{
	if(empty_loop(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	node_p del =H->next;
	H->next=H->next->next;
	free(del);
	H->date--;
}
void insert_pos(node_p H,int pos,int date)
{
	if(empty_loop(H))
	{
		printf("input empty,don't insert!\n");
		return;
	}
	if(pos<=0||pos>H->date+1)
	{
		printf("input pos error!\n");
		return;
	}
	node_p new=creat_node(date);
	node_p p=H;
	for(int i=0;i<pos-1;i++)
	{
		p=p->next;
	}
	new->next=p->next;
	p->next=new;
	H->date++;
}
node_p single_delete_head(node_p H)
{
	if(empty_loop(H))
	{
		printf("input empty,don't delete!\n");
		return NULL;
	}
	node_p p=H;
	while(p->next!=H)
	{
		p=p->next;
	}
	p->next=H->next;
	node_p temp=H->next;//暂时保存,释放头时,该地址会丢失
	free(H);
	return temp;
}
void no_head_show(node_p T)
{
	node_p p=T;
	do
	{
	printf("%d->",p->date);
	p=p->next;
	}while(p!=T);//第一次循环不判断
	printf("T\n");
}

运行结果:

三、链表与顺序表的区别

1、储存方式:链表的元素在内存中通过指针连接,不需要连续空间,存储空间是动态分配的,顺序表的元素是在内存顺序存储,通过数组下标访问,存储空间是顺序分配

2、访问效率:链表不支持随机访问,查找或访问需从头节点开始,访问效率低,顺序表支持随机访问,可通过数组下标访问,访问效率高

3、插入与删除操作:链表通过修改相关节点指针,具有较高效率,顺序表需要移动元素,效率低

4、空间利用率:链表每个元素都需要空间存储指针,空间利用率低

四、双向链表头插、头删、尾插、尾删、按位置插入、按位置删除

head.h

#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
	int date;
	struct node *next;
	struct node *pri;
}node,*node_p;
node_p creat_double_link();
node_p creat_new_node(int date);
int empty_link(node_p H);
void insert_head(node_p H,int date);
void insert_tail(node_p H,int date);
void delete_head(node_p H);
void delete_tail(node_p H);
void insert_pos(node_p H,int pos,int date);
void delete_pos(node_p H,int pos);
void show_link(node_p H);
#endif

main.c

#include"head.h"
int main()
{
	node_p H=creat_double_link();
	insert_head(H,11);
	insert_tail(H,22);
	insert_tail(H,33);
	insert_tail(H,44);
	delete_head(H);
	delete_tail(H);
	insert_pos(H,2,55);
	delete_pos(H,3);
	show_link(H);
}

test.c

#include"head.h"
node_p creat_double_link()
{
	node_p H=(node_p)malloc(sizeof(node));
	if(H==NULL)
	{
		printf("fail to apply!\n");
		return NULL;
	}
	H->next=NULL;
	H->pri=NULL;
	H->date=0;
	return H;
}
node_p creat_new_node(int date)
{
	node_p h=(node_p)malloc(sizeof(node));
	if(h==NULL)
	{
		printf("new node fail to apply!\n");
		return NULL;
	}
	h->date=date;
	return h;
}
int empty_link(node_p H)
{
	if(H==NULL)
	{
		printf("fail to apply!\n");
		return -1;
	}
	return H==NULL?1:0;
}
void insert_head(node_p H,int date)
{
	if(H==NULL)
	{
		printf("fail to apply!\n");
		return;
	}
	node_p new=creat_new_node(date);
	new->next=H->next;//插入的新节点,后继要保存它插入前头结点后的地址
	if(H->next!=NULL)//只有头结点时,后面没有元素,无需连接前驱
	{
		H->next->pri=new;//	当已有元素时,需连接前驱,插入前该节点后移,插入后该节点的前驱要保存插入节点的地址
	}
	new->pri=H;//插入节点保存头节点地址
	H->next=new;//更新头节点后继,使其保存下一个元素的地址(被插入节点)
	H->date++;
}
void insert_tail(node_p H,int date)
{
	if(H==NULL)
	{
		printf("fail to apply!\n");
		return;
	}
	node_p new =creat_new_node(date);
	node_p p=H;
	while(p->next!=NULL)//找到最后一个节点
	{
		p=p->next;
	}
	new->next=NULL;
	p->next=new;
	new->pri=p;
	H->date++;
}
void delete_head(node_p H)
{
	if(empty_link(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	node_p del=H->next;//保存要删除的位置
	H->next=H->next->next;
	H->next->next->pri=H;
	free(del);
	H->date--;
}
void delete_tail(node_p H)
{
	if(empty_link(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	node_p p=H;
	while(p->next->next!=NULL)
	{
		p=p->next;
	}
	node_p del=p->next;
	p->next=NULL;
	free(del);
	H->date--;
}
void insert_pos(node_p H,int pos,int date)
{
	if(empty_link(H))
	{
		printf("input empty,don't inserting!\n");
		return;
	}
	if(pos<=0||pos>H->date+1)
	{
		printf("input pos error!\n");
		return;
	}
	node_p p=H;
	node_p new=creat_new_node(date);
	for(int i=0;i<pos-1;i++)
	{
		p=p->next;
	}
	new->next=p->next;
	if(p->next!=NULL)//在最后插入,相当于尾插,此时插入元素后面没有元素,此条无需连接
	{
	p->next->pri=new;
	}
	p->next=new;
	new->pri=p;
	H->date++;
}
void delete_pos(node_p H,int pos)
{
	if(empty_link(H))
	{
		printf("input empty,don't delete!\n");
		return;
	}
	if(pos<=0||pos>H->date)
	{
		printf("input pos error!\n");
		return;
	}
	node_p p=H;
	for(int i=0;i<pos-1;i++)
	{
		p=p->next;
	}
	node_p del=p->next;
	if(p->next->next!=NULL)//最后一个元素相当于尾删,无需连接后面的元素
	{
		p->next->next->pri=p;
	}
		p->next=p->next->next;
		free(del);
		H->date--;
}
void show_link(node_p H)
{
	if(empty_link(H))
	{
		printf("input empty,don't ouput!\n");
		return;
	}
	node_p p=H;
	while(p->next!=NULL)
	{
		printf("%d->",p->next->date);
		p=p->next;
	}
	printf("NULL\n");
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值