单链表的复习

我们在创建结构体的时候往往不会逃过指针的使用,关于结构体

以下为单链表结构体以及单链表初始化

#include <stdio.h>
#include <stdlib.h> 
typedef struct Lnode{
	int data;//数据域 
	struct Lnode *next;//指针域 注意:这里的Lnode一定要与一开始的struct后面的一样 
}lnode,*linklist;//这里利用typedef关键字,定义名字叫Lnode的struct,typedef将lnode声明类型名称,与 Lnode一样,表示lnode可以用来声明或定义struct变量,
                //*linklist作为一个整体由typedef声明,亦被声明为类型从整体上看,(*linklist)与lnode一样,但是在类型表示中,*号代表指针,意思是说:*linklist是一个指针类型
				//那么使用效果上有什么区别呢:
linklist l;//这里写这个是为了防止野指针问题,然后如果这里写的是lnode l则表示结构体变量,结构体变量用的是. 而linklist是结构体指针,结构体指针用的是->				
//单链表的初始化 
bool Initlist(linklist &l)
{
	l=(linklist)malloc(sizeof(lnode));
	l->next=NULL;
	return true;
} 
int main()
{
	if(Initlist(l)==1) printf("初始化成功\n");
	else printf("初始化失败\n");
}

可以看到图中定义了两个声明,lnode和*linklist

在使用lnode定义结构体变量时,通常写lnode l;这里的l称为结构体变量,结构体变量代表的是节点本身,访问这个节点写成l.data,

在使用linklist定义结构体指针时,通常写成linklist l,这里的l称为结构体指针,结构体指针指向这块节点,访问这个节点写成l->data,

linklist l;也就相当于写成lnode *l;而对于结构体指针l来说,l->data;同时也可以写成(*l).data;

*号表示取内容

当然这里的代码表示带头结点的单链表,不带头结点的单链表只需将l初始化为NULL即可

增加一个头节点方便运算,接下来我们讨论的单链表皆为带头结点的

接下来是单链表的所有操作,注释比代码多:>

#include <stdio.h>
#include <stdlib.h> 
typedef struct Lnode{
	int data;//数据域 
	struct Lnode *next;//指针域 注意:这里的Lnode一定要与一开始的struct后面的一样 
}lnode,*linklist;//这里利用typedef关键字,定义名字叫Lnode的struct,typedef将lnode声明类型名称,与 Lnode一样,表示lnode可以用来声明或定义struct变量,
                 //*linklist作为一个整体由typedef声明,亦被声明为类型从整体上看,(*linklist)与lnode一样,但是在类型表示中,*号代表指针,意思是说:*linklist是一个指针类型
				 //那么使用效果上有什么区别呢:
linklist l;//这里写这个是为了防止野指针问题,然后如果这里写的是lnode l则表示结构体变量,结构体变量用的是. 而linklist是结构体指针,结构体指针用的是->
				
//单链表的初始化 
bool Initlist(linklist &l)
{
	l=(linklist)malloc(sizeof(lnode));
	l->next=NULL;
	return true;
}

//求表长操作
//这里的表长指的是数据节点的个数,若只有头节点,则头结点的next指向空,则表长为0 
int length(linklist l)
{
	int i=0;
	lnode *p=l;
	while(p->next!=NULL)
	{
		i++;
		p=p->next;
	}
	return i;
}

//按照序号查找结点
//步骤:从单链表的第一个有值的节点开始,往后查找找到第i个节点时返回这个节点 
lnode *GetElem(linklist l,int i)
{
	int j;
	lnode *p;
	p=l;//从头节点开始看 
	while(p!=NULL&&j<i)
	{
		p=p->next;
		j++;
	}
	return p;
	 
	//或者写成
	/*p=l->next;//从第一个有值的结点开始看 
	while(p!=NULL&&j<i-1)
	{
		p=p->next;
		j++;
	}
	return p;*/
}

//按照值查找表结点
lnode *LocateElem(linklist l,int e)
{
	lnode *p;
	p=l->next;
	while(p->data!=e&&p!=NULL)
	{
		p=p->next;
	}
	return p;
} 

//插入节点后插操作
//步骤:1,先检验插入位置的合法性
//     2,然后然后找到插入位置的直接前驱在其后插入
//头节点是第0个节点 
bool Listinsert(linklist &l,int i,int e)
{
	int j=0;
	lnode *p=l;
	while(p!=NULL&&j<i-1)//注意这里的-1很容易漏,最后还有一次循环 
	{
		p=p->next;
		j++;
	}
	//我们找到第i-1个结点后进行判断,判断该结点是否合法
	if(p==NULL) return false;//这里没有写p->next==NULL是因为可以插在表尾 
	lnode *s=(linklist)malloc(sizeof(lnode));//开辟新区域用来插入结点 
	s->data=e;
	//注意接下来的顺序 
	s->next=p->next;
	p->next=s;
	return true;
	//插入结点前插操作
	/*int temp;
	s->next=p->next;
	p->next=s;
	temp=p->data;
	p->data=s->data;
	s->data=temp;*/ 
}

//删除节点操作
//步骤:1,先判断删除的位置是否合法
//      2,然后找到删除节点的直接前驱,将前驱的next指向要删除节点的前一个节点,然后进行断链合链操作 
bool Listdelete(linklist &l,int i,int &e)
{
	int j=0;
	lnode *p;
	p=l;//从头节点开始,头节点为第0个节点
	while(p!=NULL&&j<i-1)
	{
		p=p->next;
		j++;
	}
	if(p==NULL||p->next==NULL) return false;//注意这里和插入操作不同 ,这里的p->next==NULL表示的是要删除的位置超出了当前表的长度
	//进行删除操作
	e=p->next->data;
	q=p->next;
	p->next=q->next;
	free(q);
	return true; 
	//或者说还可以这样写,将要删除节点的后继结点赋值给要删除的结点,再将要删除的节点的后继结点删掉,假设p为要删除的结点 
	/*q=p->next
	  p->data=p->next->data;
	  p->next=q->next;
	  free(q)*/ 
} 

//利用头插法建立单链表
//步骤:从一个空表开始,生成新节点,并将读取到的数据存放到数据域中,然后将新节点插入到当前链表的表头,即头节点之后 
lnode *List_HeadInsert(linklist &l)
{
	lnode *s;
	int x;
	//这一部分内容为初始化也可以利用上面创建的函数Initlist(l) 
	l=(lnode *)malloc(sizeof(lnode));//开辟一块属于头结点的区域 
	l->next=NULL;//这一步是将链表初始化为空链表
	scanf("%d",&x);//这个地方你输入的值为第一个有值结点的值,其实就是起到了一个起头的作用 
	while(x!=9999)//输入9999结束 
	{
		//这里开始头插法,这个s用来开辟新的节点区域 
		s=(lnode *)malloc(sizeof(lnode));
		s->data=x;
		//这里其实是只有第一次是比较难想的因为你只要进入第二次插入,或者说你往后看,都是相当于在头结点和第一个有值结点间进行插入,这样的话就比较好想
		//其实就是前面说的在第i个位置进行插入,只不过这里的i换成了1,我们在第一个位置进行插入,找到前驱节点头结点,然后进行后插操作就是这两行代码 
		s->next=l->next; 
		l->next=s;
		scanf("%d",&x); 
	}
	//此段循环代码和第4行开始的代码类似,都是表示单链表的后插操作,只不过这里的i固定为1 
	 return l;//返回头结点 
} 

//采用尾插法建立单链表
//步骤:头插法虽然简单但是输出的数据和输入的数据顺序不一致,若希望两者顺序一致,可采用尾插法
//     该方法将新节点插入到链表的表尾,为此必须加上一个尾指针r,使其始终指向该链表的尾结点
lnode *List_TailInsert(linklist &l)
{
	int x;
	l=(lnode *)malloc(sizeof(lnode));//创建头结点
	lnode *s,*r=l;//开始时尾指针位于头结点 
	l->next=NULL;
	scanf("%d",&x);//输入插入到第一个结点的数据 
	while(x!=9999)
	{
		s=(lnode *)malloc(sizeof(lnode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	} 
	r->next=NULL;
	return l;//返回头结点 
} 

int main()
{
	if(Initlist(l)==1) printf("初始化成功\n");
	else printf("初始化失败\n");
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值