我们在创建结构体的时候往往不会逃过指针的使用,关于结构体
以下为单链表结构体以及单链表初始化
#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");
}