C语言数据结构:链表建立(单链表头插法尾插法、循环链表、双链表、静态链表)

以书本实例完善为主,书上内容多则补充,少则自己写,为了统一格式,各链表都带头结点。

1.头文件和宏定义(各链表通用)

#include<stdio.h>
#include<stdlib.h>  //malloc、realloc、free函数
#include<string.h>

#define ElemType int 
#define MaxSize 6  //静态链表最大长度

2.头插法建立单链表

typedef struct LNode
{
 ElemType data;
 struct LNode *next;  //此处next为只能指向LNode(即链表结点)的结构体指针变量,因为结点为结构体
}LNode,*LinkList;
LinkList HeadInsert_List(LinkList L)  //头插法,返回一个结构体类型的结点变量,个人认为返回头结点毫无必要
{
 int x,i=1;
 L=(LinkList)malloc(sizeof(LNode)); //头结点分配空间,若不分配,L为头指针,则该链表为没有头结点的单链表
 L->next=NULL;
 LNode *s,*p=L;
 printf("请输入头插法链表%d号数据(输入9999结束):",i);
 scanf("%d",&x);
 while(x!=9999)  //因为x申明在先,所以循环外先要赋一次值
 {
 i++;
 printf("请输入头插法链表%d号数据(输入9999结束):",i);
 s=(LNode*)malloc(sizeof(LNode));
 s->data=x;
 s->next=L->next;
 L->next=s;
 scanf("%d",&x); 
 }
 while(p->next!=NULL)
 {
  printf("%d ",p->next->data);
  p=p->next;
 }
 printf("\n");
 printf("插入成功!");
 return L;
}

运行结果:
空间复杂度

可以看到,因为是头插法,数据在链表中其实是倒序存放的,为了统一,以下链表均采用尾插法。

3.尾插法建立单链表

 LinkList TailInsert_List(LinkList L)  //尾插法,主要步骤与头插法类似,不再过多注释
{
 int x,i=1;
 L=(LinkList)malloc(sizeof(LNode)); //头结点分配空间,即带头结点
 LNode *s,*p=L,*r=L;   //与头插法主要不同点在于建立
 printf("请输入尾插法链表%d号数据(输入9999结束):",i);
 scanf("%d",&x);
 while(x!=9999)
 {
 i++;
 s=(LNode*)malloc(sizeof(LNode));
 s->data=x;
 r->next=s;
 r=s;
 printf("请输入尾插法链表%d号数据(输入9999结束):",i);
 scanf("%d",&x);
 }
 printf("插入成功!\n数据为:");
 while(p->next!=NULL)
 {
  printf("%d",p->next->data);
  p=p->next;
 }
 return L;
}


void main()
{
 LinkList L;
 L=TailInsert_List(L);
}

运行结果:
在这里插入图片描述
可以看到尾插法运行结果为正序

4.尾插法建立双链表
双:两个
链:链接(c语言中为指针)
表:线性表
双链表即表示结点有两个指针的线性表

typedef struct DNode
{
 ElemType data;
 struct DNode *prior,*next;
}DNode,*DLinkList;


DLinkList TailInsert_List(DLinkList L)  //尾插法建立双链表,返回头结点
{
 L=(DNode *)malloc(sizeof(DNode));
 L->next=NULL;
 L->prior=NULL;  //头结点初始化前后指针都为空
 int x,i=1;
 DNode *s,*r=L,*p=L;
 printf("请输入尾插法双链表%d号数据(输入9999结束):",i);
 scanf("%d",&x);
 while(x!=9999)
 {
  i++;
  printf("请输入尾插法双链表%d号数据(输入9999结束):",i);
  s=(DNode *)malloc(sizeof(DNode));
  s->data=x;
  s->next=NULL;
  s->prior=r;
  r->next=s;  //与单链表稍有不同,不加赘述了
  r=s;
  scanf("%d",&x);
 }
 while(p->next!=NULL)
 {
  printf("%d ",p->next->data);
  p=p->next;
 }
 printf("建立成功!");
 return L;
} 


void main()
{
 DNode *L;
 TailInsert_List(L);
}

运行结果

在这里插入图片描述
5.循环链表

//循环链表
typedef struct CNode  //C即为circle(循环)的缩写
{
 ElemType data;
 struct CNode *next;
}CNode,*CLinkList;


CLinkList TailInsert_List(CLinkList L)  //尾插法建立循环链表
{
 int x,i=1;
 L=(CLinkList)malloc(sizeof(CNode)); //头结点分配空间,即带头结点
 L->next=L;
 CNode *s,*p=L,*r=L;
 printf("请输入尾插法链表%d号数据(输入9999结束):",i);
 scanf("%d",&x);
 while(x!=9999)
 {
 i++;
 s=(CNode*)malloc(sizeof(CNode));
 s->data=x;
 r->next=s;
 s->next=L;  //与建立单链表最大不同就是表尾指针要指向头结点
 r=s;
 printf("请输入尾插法循环链表%d号数据(输入9999结束):",i);
 scanf("%d",&x);
 
 }
 while(p->next!=L)
 {
  printf("%d ",p->next->data);
  p=p->next;
 }
 printf("%d ",p->next->next->data);  //输出当前p指向的下下个元素数据,即位置1的数据,证明其循环性成立
 return L;
}


void main()
{
 CNode *L;
 TailInsert_List(L);
}

运行结果:
在这里插入图片描述
为了证明该链表的循环性,在函数运行结束后,输出尾结点指向的下下个数据元素(即元素1),能输出则得证

6.静态链表(个人认为是链表中较难实现,也最少考的内容)
思想:先建立辅助数组,数组中data为空,next为满,从1到MaxSize-1,尾结点next为0(书本中要求为-1),每次插入数据从1号(注意因为是数组,1号实际上是第二个结点)开始逐个插入,顺序可以自己决定,只需要修改对应next值即可(此处又有一个注意点:若要随机插入,需要判断目标插入位置是否已有数据,即数据域是否有内容或指针域是否已被修改),为了简化理解,代码以顺序插入为例。

typedef struct 
{
 ElemType data;
 int next;
}SLinkList[MaxSize];


void reserve(SLinkList *L)
{
 for(int i=0;i<MaxSize-1;i++)
 {
  L[i]->next=i+1;
  L[i]->data=-1;
 }
 L[MaxSize-1]->next=0;
}


int malloc_L(SLinkList *L)
{
 int i=L[0]->next;
 if(L[0]->next)
 {
  L[0]->next=L[i]->next;
 }
 return i;
}


int init_L(SLinkList *L)
{
 reserve(L);
 int a=malloc_L(L);
 int temp=a;
 for(int i=1;i<4;i++)
 {
  int j=malloc_L(L);
  L[temp]->next=j;
  L[j]->data=i;
  temp=j;
 }
 L[temp]->next=0;
 return a;
}


void Display(SLinkList *L,int a)
{
 int temp=a;
 while (L[temp]->next)
 {
  printf("%d,%d ",L[temp]->data,L[temp]->next);
  temp=L[temp]->next;
 }
 printf("%d,%d",L[temp]->data,L[temp]->next);
}


void main()
{
 SLinkList L[MaxSize];
 int a=init_L(L);
 printf("静态链表为:\n");
 Display(L,a);
}

若不理解可以参考:详细过程

总结:链表这一部分是数据结构中非常基础、非常常考、也非常多变,适合出题的一章,务必了解各种链表的建立(如上)和单链表的增删查改、整合、逆置,这些内容会在后面完成。链表基本操作

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

事多做话少说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值