【线性表】单链表及其基本运算和应用

单链表的c语言定义
typedef struct Node {
	ElemType data;/*数据域*/
	struct Node *next;/*指针域*/
} Node,*Linklist;/*给node起两个别名,这两个别名等效*/
LinkLIst L;/*L为单链表的头指针,也称为单链表L*/

LinkList 与 Node*同为结构指针类斜体样式型,这两种类型是等价的。

通常我们习惯上用LinkList说明指针变量,强调它是某个单链表的头指针变量,用
Node*来定义指向单链表中节点的指针。

单链表的基本运算
一、求带头节点单链表的长度
int listlength(linklist L){
	node *p;
	p=->next;
	j=0;/*用来存放单链表的长度*/
	while(p!=NULL){
		p=p->next;
		j++;
	}
	return j;
} 
二、建表
1.建立空表
InitList(linklist *L)/*建立空表*/{
	L=(linklist*)malloc(sizeof(node));
	L->next=NULL;
} 
2.头插法建表
linklist creatfromhead(linklist l){
	node *s;
	char c;
	int flag=1;/*设置一个标志,初值为1,当输入“$”时,flag为0,建表结束*/
	while(flag){
		c=getchar();
		if(c!='$'){
			s(node*)malloc(sizeof(node))
			/*申请新结点s*/
			s->data=c;
			s->next=L->next;
			/*将结点s头插入链表L*/
			L->next=s; 
		}
		else flag=0;
	}
}
3.尾插法建表
linklist createfromtail(linklist L){
	linklist L;
	node *r,*s;
	char c;
	int flag=1;/*设置一个标志,初值为1,当输入“$”时,flag为0,建表结束*/
	r=L;/*r指针始终动态指向链表的当前表尾,以便做尾插入,其初值指向头结点*/
	while(flag){
		c=getchar();
		if(c!='$'){
			s=(node*)malloc(sizeof(node));
			s->data=c;
			r->next=s;
			r=s;/*r就是当前尾结点*/
		} 
		else{
			flag=0;
			r->next=NULL;/*将最后一个结点的next链域置为空,表示链表结束*/
		}
	}
} 
三、查找
1.按序号查找
node *get(linklist L,int i)
/*在带头结点的单链表L中查找第i个结点,
若找到(1<=i<=n),则返回该结点的存储位置,否则返回NULL*/
{
	int j=0;/*计数器*/
	node *p;
	p=L;/*从头结点开始扫描*/
	while((p->next!=NULL)&&(j<i)){
		p=p->next;/*扫描下一结点*/
		j++;/*已扫描结点计数器*/
	}
	if(i==j)return p;/*找到了第i个点*/
	else return NULL;/*找不到,i<=0或i>n*/	
} 
2.按值查找
node *locate(linklist l,elemtype key)
/*在带头结点的单链表L中查找其结点值等于key的结点,
若是找到则返回该结点的位置p,否则返回NULL*/
{
	node *p;
	p=l->next;/*从表中第一个结点比较*/
	while(p!=NULL){
		if(p->data!=key)
		p=p->next;
		else break;/*找到结点key退出循环*/
	} 
	return p; 
}
四、单链表插入
void inslist(linklist L,int i,elemtype e){
	node *pre,*s;
	int k=0;
	pre=L;
	while(pre!=NULL&&k<(i-1))
	/*在第i个元素之前插入,则先找到第i-1个数据元素的存储位置
	使pre指针指向它*/
	{
		pre=pre->next;
		k++; 
	}
	if(!pre)/*如果当前位置pre为空,表示已找完但还未数到第i个
	说明插入位置不合理*/
	{
		printf("插入位置不合理");
		return ERROR; 
	}
	s=(node*)malloc(sizeof(node));
	/*为s申请一个新结点并由s指向它*/
	s->data=e;
	/*将待插入结点的值e赋给s的数据域*/
	s->next=pre->next;/*完成插入操作*/
	pre->next=s;
	return OK; 
} 
五、单链表删除
void dellist(linklist L,int i,elemtype *e)
/*在带头结点的单链表L中删除第i个元素,
并将删除的元素保存到变量*e中。*/
{
	node *p,*r;
	int k=0;
	p=L;
	while(p->next!=NULL&&k<(i-1))
	/*寻找被删除结点i的前驱结点i-1使p指向它*/
	{
		p=p->next;
		k++; 
	}
	if(k!=i-1)
	/*即循环是因为p->next=NULL而跳出来的*/
	{
		printf("删除位置i不合理");
		return error; 
	}
	r=p->next;
	p->next=p->next->next;
	*e=r->data;
	free(r);/*释放被删除结点所占内存空间*/
} 
算法应用示例
求两个集合的差
void difference(linklist la,linklist lb) {
	node *pre,*p,*q,*r;
	pre=la;
	p=la->next;
	while(p!=NULL) { /*逐个确定A表一个元素*/
		q=lb->next;/*查是否属于b表*/
		while(q!=NULL&&q->data!=p->data) {
			q=q>next;
		}
		if(q!=NULL) {
			r=p;
			pre->next=p->next;
			p=p->next;
			free(r);
		} else {
			pre=p;
			p=p->next;
		}
	}
}
带头结点单链表就地逆置问题
【问题分析】逆置就是使得表中内容由原来的(a1,a2,…,ai-1,ai,ai+1, …,an)变为 (an,an-1,…,ai+1,ai,ai-1, …,a1)。就地逆置就是不需要额外申请结点空间,只需要 利用原有的表中的节点空间。若对顺序表中的元素进行逆置,可以借助于“交换”前后相应 元素;对单链表中的元素进行逆置,则不能按“交换”思路,因为对于链表中第 i 个结点需 要顺链查找第 n-i+1(链表长度为 n)个结点,逆置链表的时间复杂度将达 O(n2)。

【算法思路】用头插法完成

  • 【初始化】逆置链表L初始为空表,指针p指向原表当前处理结点
  • 【头插法】依次取原链表中当前结点p
    将其作为第一个结点插入到逆置链表L的表头L
    q为保存原链表当前结点的下一个处理位置

在这里插入图片描述
【算法描述】

void reverselist(linklist l)
//逆置带头结点的单链表L 
{
	p=l->next;//记录原表第一个元素结点的地址 
	l->next=NULL;//从将头结点的next域置空得新空链表
	while(p!=NULL){
		q=p->next;/*q 指针保留原链表当前处理结点的下一个结点*/
		p->next=l->next;
		l->next=p;/*p 指向下一个待插入的结点*/
		p=q;/*p 指向下一个待插入的结点*/
	}
}
二进制数加一运算

建立一个带头结点的线性链表,用以存放输入的二进制数,链表中每个结点的
data 域存放一个二进制位。并在此链表上实现对二进制数加 1 的运算

【问题分析】
①建链表:带二进制数可用带头结点的单链表存储,第一个结点存储二进制数的最高位,依次存储,最后一个结点存储二进制数的最低位。
②二进制加法规则:实现二进制数加 1 运算,方向从低位往高位找到第一个值为 0 的位,把该位改成1,其后所有各位改成0
在这里插入图片描述在这里插入图片描述

③链表实现二进制加 1 时,从高位往低位与运算方向正好相反,从第一个结点开始找,找出最后一个值域为 0 的结点,把该结点值域赋为 1,其后所有结点的值域赋为 0。

④若在链表中未找到值域为 0 的结点,则表示该二进制数各位均为 1,此时,申请一新结点,值域为 1,插入到头结点与原链表的第一个结点之间,成为新链表的第一个结点,其后所有结点的值域赋为 0。

【算法描述】

void binadd(linklist l) {
	node *q,*r,*s;
	q=l->next;
	r=l;
	while(q!=NULL)
	//找到最后一个值域为0的点
	{
		if(q->data==0) r=q;
		q=q->nest;
	}
	if(r!=l) 
	//能够找到值域为0的点
	{
		r->data=1;/*将最后一个值域为 0 的结点的值域赋为 1*/
	} else //该二进制数各位均为 1
	{ 
		s=(node*)malloc(sizeof(node));/*申请新结点存放最高进位*/
		s->data=1;/*值域赋为 1*/
		s->next=l->nest;
		l->nest=s;/*插入到头结点之后*/
		r=s;
	}
	r=r->nest;
	while(r!=NULL) 
	/*将后面的所有结点的值域赋为 0*/
	{ 
		r->data=0;
		r=r->nest;
	}
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值