线性表--顺序表--单向链表(四)

103 阅读4分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

写在前面: 大家好,我是 花狗Fdog ,来自内蒙古的一个小城市,目前在泰州读书。 很感谢能有这样一个平台让我能够在这里分享所学所感。 我喜欢编程,喜欢代码,喜欢去做一个程序员。 努力学习,争取多年后,给亲人更好的生活。 QQ/WX:2506897252 欢迎交流。

现在来讲讲单向链表,首先,链表和数组不同,数组中元素的内存地址是连续的,而链表中的元素内存地址是随机的。由于链表中的节点的数据类型是相同的,并且是随机存储,所以我们不能像数组那样只需要知道头节点就可以访问整个链表,我们必须在每个节点中存储下一个节点的地址,就好比狗链子中每一节的口子,用来连接下一节链子,只有这样,我们才能一节一节访问整个链表。 ==数组是这样使用内存,内存地址是连续的==

在这里插入图片描述 ==而链表是这样使用内存的,所有他们必须有指向下一节点的指针== 在这里插入图片描述 看到到这里,你对链表应该有一个小的认识了吧,那么下面我们就来定义一个链表吧。

1.定义链表

 typedef struct list
 {
  int x;
  struct list * next;
 }list;

想一想,定义了链表就相当于我们有了每节小链子的模具,接下来,我们就该造小链子以及绳子了。

2.头节点初始化

list * InitListHead() //初始化 
{
 list *Phead = (list *)malloc(sizeof(list));//创建头结点
 Phead->x = 0;  //该变量可存放该链表长度
 Phead->next = NULL;
 return Phead;       //创建后返回该头指针
}

头节点的数据可以存放比如链表的长度等等,接下来,我们只需要重复创建节点,这便是链表,这里要注意一下的是,单向链表包括头插入和尾插入,下面将分开讲解。

3.头插法

void HeadList(list * L,int e)//头插法
{
 list * Pbady = (list *)malloc(sizeof(list));//创建一个节点
 Pbady->x = e;
 Pbady->next = NULL;
 if (L->next == NULL)
 {
  L->next=Pbady;
 }
 else
 {
  Pbady->next = L->next;
  L->next = Pbady;
 }
 L->x++;
}
}

避免生硬的代码,我们用图来说明。 在这里插入图片描述 不难看出,使用头插法的数据是逆序排列的,后来的反而排在前面,这也是头插和尾插的区别之一。

4.尾插法

void TrailList(list * LA,list ** LB,int e)//尾插法
{
  list *Pbady = (list*)malloc(sizeof(list));
  Pbady->x = e;
  if (LA->next == NULL)
  {
   LA->next = Pbady;
  }
  else
  {
   (*LB)->next = Pbady;
  }
  Pbady->next = NULL;
  *LB = Pbady;
  LA->x++;
}

尾插法相对于头插法多了一个指针,如果代码看着懵,那我们依旧上图来说。 在这里插入图片描述 尾插法不像头插法,只需要在开头插入就可以,而尾插入需要遍历整个链表并找到最后,如果链表足够长,每次都遍历一遍,显然不科学,所以我们想到用一个指针来随时记录最后一个节点的位置,并指向最后一个节点,这样,每当我们有新节点的时候,只需要在该指针后面插入即可。并更新该指针,至于为什么使用二级指针可查看该文。

指针作形参的一些问题

接下来来看一下链表的基本运算。

5.按序号查找内容

int NumFindList(list *L,int e)//按序号查找
{
 if (e <= 0)
 {
  return -1;
 }
 int i = 0;
 int j = L->x;
 list * P = L;
 while (P != NULL&&i <= j)
 {
  if (i == e)
  {
   printf("该内容为%d\n", P->x);
   break;
  }
  P = P->next;
  i++;
 }
}

6.按值查找

void ValueFindList(list * L,int e)//按值查找
{
 int i = 0;
 int j = L->x;
 list * P = L;
 while (P != NULL&&i <= j)
 {
  if (P->x == e)
  {
   printf("已找到\n");
  }
  P = P->next;
  i++;
 }
}

7.求链表长度

int LengthList(list * L)//链表长度
{
 return L->x;//这里我们只需要访问头节点中的数据即可
}

8.插入操作

void InsertList(list * L,int i,int e)//插入操作
{
 if (i > L->x)
 {
  printf("插入位置不合法\n");
  return ;
 }
 list * Pbady = (list *)malloc(sizeof(list));
 list *P = L->next;
 int a = 1;
 Pbady->x = e;
 while (P != NULL)
 {
  if (a == i-1)
  {
   Pbady->next = P->next;
   P->next = Pbady;
   L->x++;
   break;
  }
  P = P->next;
  a++;
 }
}

9.删除操作

void DelList(list * L,int i)//删除操作
{
 if (i > L->x)
 {
  printf("插入位置不合法\n");
  return;
 }
 list * P = L->next;
 list * P_2 = NULL;
 int a = 1;
 while (P != NULL)
 {
  if (a == i-1)
  {
   P_2 = P->next;
   P->next = P->next->next;
   P_2->next = NULL;
   free(P_2);
   L->x--;
   break;
  }
  P = P->next;
  a++;
 }
}

10.显示链表现有内容

void ShowList(list * L)//显示链表
{
 list * P = L;
 printf("该链表共有%d个元素\n", P->x);
 P = L->next;
 while (P!= NULL)
 {
  printf("%d\n", P->x);
  P = P->next;
 }
}

11.释放内存

void FreeList(list * L)
{
 list * P;
 if (L == NULL)
 {
  return ;
 }
 while (L)
 {
  P = L->next;
  free(L);
  L = P;
 }
}

好了,单向链表的讲解就到这里。

如果有什么错误,欢迎指出,欢迎讨论。 ==每文一句:不要总是用眼泪去打动去挽留,有时侯你的眼泪适得其反,微笑,一定要自信的微笑着面对一切!==