9.8线性表之单链表

9.8线性表之单链表

链表的概念

链表,别名:链式存储结构

链表的特点:

  • 不限制数据的物理存储状态

    • 存储的数据物理位置是随机的不是连续的

  • 每个数据存储时都配备一个指针,用于指向自己的直接后继元素--->前驱和后继

使用链表存储数据{1,2,3}图示:

链式存储结构

数据元素随机存储,并通过指针表示数据之间逻辑关系的存储结构就是链式存储结构

链表的组成部分

  • 数据元素本身,数据域

  • 指向直接后继元素的指针,指针域

链表中元素存储结构示意图:

特点:

  • 上诉结构在链表中称为节点。链表实际存储的是一个一个的节点,真正的数据元素包含在这些节点中

节点存储结构图示:--->简单结构

C语言实现节点的结构体

typedef struct Link{
   char element; //数据域
   struct Link * next; //指针域,指向直接后继元素
}link;
/*
link为节点名,每个节点都是一个 link 结构体
类似宏,一个link就包含数据域和指针域,指针域是一个指针变量
*/

Go实现:

/*
创建链表的节点结构体:
1、数据域
2、指针域--->一个指针变量,属于该结构体的指针变量
*/
type Link struct {
/*创建数据域*/
element int
/*创建指针域--->一个指针变量,属于该结构体*/
*Link
}

由于指针域中的指针要指向的也是一个节点,因此要声明为 Link 类型(这里要写成 struct Link* 的形式)

头节点、头指针、首元节点

一个完整的链表由以下几个部分构成:

  • 头指针:一个普通的指针。永远指向链表第一个节点的位置。用于指明链表的位置,便于后期找到链表并使用表中的数据

  • 节点:

    • 头节点:不存任何数据的空节点,通常作为链表的第一个节点--->头节点是必须的。方便解决某些实际问题

    • 首元节点:链表中称第一个存有数据的节点为首元节点--->只是一个称谓,没有实际意义

    • 其他节点:链表中其他的节点

链表中有头节点时,头指针指向头节点;反之,若链表中没有头节点,则头指针指向首元节点。

完整链表的结构图示:

链表的创建

创建一个链表需要做的事情:

  • 声明一个头指针

  • 声明一个头节点

  • 创建多个存储数据的节点

创建一个存储 {1,2,3,4} 且无头节点的链表示例代码:--->要结合上面的结构体来看

//初始化link结构体
link * initLink(){
   link * p = NULL; //创建一个头指针--->该指针式link结构体的一个实例。包含了数据域和指针域
   link * temp = (link*) malloc(sizeof(link)); //创建首元节点--->第一个拥有数据的节点--->也是一个link结构体的实例
   //首元节点初始化--->获取结构体成员
   temp->elem = 1;
   temp->next = NULL;
   //使头指针指向首元节点
   p = temp;
   
   //从第二个节点开始创建节点
   for(int i=2;i<5;i++){
       //创建一个新节点并且初始化
       link *a = (link*)malloc(sizeof(link));
       //初始化数据域与指针域
       a->elem = i;
       a->next = NULL;
       //将上诉的首元节点与新节点建立逻辑关系
       temp->next = a; //next是结构体的一个link结构体指针,a本身就是一个结构体
       //指针temp每次都指向新链表的最后一个节点,其实就是 a节点,写temp=a也对
       temp = temp->next;
  }
   //返回建立的节点,只返回头指针p即可。通过头指针找到整个链表
   return p;
}

创建一个含头节点的链表示例代码:

link * initLink(){
   link * p = NULL; //这是一个头指针
   link * f = (link*)malloc(sizeof(link)); //这是一个头节点
   p = f; //这是让头指针指向头节点--->赋值操作
   
   //开始创建其他节点
   for(int i=1;i<5;i++){
       //创建其他节点
       link * a=(link)malloc(sizeof(link));
       //初始化数据域和指针域
       a->elem = i; //这是数据域
       a->next = NULL; //这是指针域
       //让头节点与首元节点发生逻辑联系--->用头指针的指针域指向首元节点
       f->next=a;
       //指针每次都指向新链表的最后一个节点
       f=f->next //其实就是f=a->next
  }
   //返回头指针
   return p;
}

调用 initLink 函数,创建一个存储 {1,2,3,4} 的链表示例代码:

#include <stdio.h>
#include <stdlib.h>

//创建节点结构体--->一个节点应该包含的成员
typedef struct Link{
   /*数据域*/
   int element;
   /*指针域*/
   struct Link *next; //一个指针变量,属于结构体的指针变量
}link;

//初始化链表函数
link * initLink();

//定义初始化方法
link * initLink(){
   /*创建头指针*/
   link * f = NULL;
   /*创建首元节点*/
   link * temp = (link*)malloc(sizeof(link));
   //初始化首元节点
   temp->elem=1;
   temp->next=NULL;
   
   //循环创建其他节点
   for(int i=2;i<5;i++){
       //创建其他节点
       link * a=(link*)malloc(sizeof(link));
       //初始化其他节点数据
       a->elem=i;
       a->next=NULL;
       
       //让首元节点与其他节点发生逻辑联系--->首元节点的指针域指向下一个节点的数据域
       temp->next = a;
       //首元节点的数据域指向下一个节点的数据域
       temp=temp->next;
  }
   //返回头指针
   return p;
}

//输出链表函数--->指针数据
void display(link *p);

//定义输出方法
void display(link *p){
   //将temp指向头节点
   link * temp = p;
   //只要temp指针指向的结点的next不是Null,就执行输出语句
   while(temp){
       printf("%d", temp->elem);
       temp = temp->next; //指向下一个节点指针域
  }
   printf("\n")
}

如果使用带有头节点创建链表的方式,则输出链表的 display 函数需要做适当地修改:--->交换输出和指向的顺序,先指向在输出

void display(link *p){
   //将temp指向头节点
   link * temp = p;
   //只要temp指针指向的结点的next不是Null,就执行输出语句
   while(temp){
       temp = temp->next; //指向下一个节点指针域
       printf("%d", temp->elem);
  }
   printf("\n")
}

 

posted @ 2021-09-08 19:43  俊king  阅读(137)  评论(0编辑  收藏  举报