【C语言之线性表链式存储结构】

C语言之线性表链式存储结构

文章目录

  • C语言之线性表链式存储结构
  • 前言
  • 一、线性表链式存储结构定义
  • 二、相关概念
    • 1.结点
    • 1.头指针
  • 三、代码描述
    • 1.单链表结点定义
    • 1.单链表的创建
    • 2.单链表的查找
    • 3.在单链表中,替换某一个位置的数据
    • 4.在单链表中,某一个位置插入数据
    • 4.在单链表中,某一个位置删除数据


前言

线性表存在不足的解决办法:`
线性表最大的缺点就是插入和删除时需要移动大量元素,这需要耗费大量时间;因此就引出链式存储结构,用任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续。
在这里插入图片描述


一、线性表链式存储结构定义

定义:
以前顺序结构中,每个数据元素只需要存数据元素就可以了,但链式结构中,为了将链表连接起来,每个元素不仅要存储数据元素信息,还需要存储它的后继元素的存储地址。
在这里插入图片描述

二、相关概念

1.结点

链表结点由数据域(存放本身信息)和指针域(指向后继结点的指针)构成。如下图所示:
在这里插入图片描述

1.头指针

对于线性表来说,总得有个头有个尾,链表也不例外,我们把链表中的第一个结点的存储位置叫做头指针,整个链表的存取就必须是从头指针开始进行了。
最后一个结点的指针为空(NULL)。
有时候我们为了更方便的对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点。
头结点的数据域可以不存储任何信息,也可以存储如线性表长度等附加信息。
在这里插入图片描述
空链表:
在这里插入图片描述

带头结点的单链表:
在这里插入图片描述
不带头结点的单链表:
在这里插入图片描述

三、代码描述

1.单链表结点定义

typedef int ElemType;可以随着数据元素类型不用,自己定义
链表的结构体
struct Node
{ElemType data;struct Node* next;
}Node;typedef  struct Node* LinkList;链表指针别名

总这个结构定义中,我们也可以知道,结点由存放数据元素的数据域和存放后继结点地址的指针域组成。假设p是指向线性表第i个元素的指针,则该结点ai的数据域,可以用p->data来表示,结点ai的指针域,可以用p->next来表示。p->next指向(意思就是存储第i个元素的地址)第i+1个元素。也就是说,如果p->data=ai,p->next->data=ai+1;
在这里插入图片描述


1.单链表的创建

单链表创建算法思路:

  • 初始化空链表L-创建头结点
  • 声明中间变量指向头结点,用于遍历链表
  • 循环
  • 生成新的结点
  • 新的结点指针指向头结点(指针)
  • 头结点指针指向新结点
头插法
LinkList CreatListHead(int len)
{LinkList L = (LinkList)malloc(sizeof(Node));//创建个头节点LinkList temp=L;                   //声明一个中间变量,指向头结点,用于遍历链表(曾因没有这个中间变量而出错)temp->next = NULL;for (int i=0;i<len;i++){LinkList p= (LinkList)malloc(sizeof(Node)); scanf_s("%d",&p->data);p->next = temp->next;     //新结点的next指针,指向开始结点(temp->next是头结点的地址)temp->next = p;                //头结点的next指针指向新结点}return (LinkList)L;
}

在这里插入图片描述
解释说明:p->next是下一个结点指针的地址
p是结点指针

尾插法

链表的创建,建立带头节点的单链线性表L,随机产生N个元素值
LinkList CreatListTail(int len)
{LinkList L = (LinkList)malloc(sizeof(Node));创建个头节点LinkList temp = L;                   声明一个中间变量,指向头结点,用于遍历链表(曾因没有这个中间变量而出错)temp->next = NULL;for (int i = 0; i < len; i++){LinkList p = (LinkList)malloc(sizeof(Node));scanf_s("%d", &p->data);temp->next = p;   头结点指向新的结点(存储新结点地址)temp = p;                将新结点变成头结点等待下一个新结点插入}temp->next = NULL;将最后一个结点的NEXT结点为空,表示链表结束return (LinkList)L;
}

2.单链表的查找

因为链表不支持随机访问,即链表的存取方式是顺序存取的(注意“存储”与“存取”是两个不一样的概念),所以要查找某结点,必须通过遍历的方式查找。例如:如果想查找第3个结点,必须先遍历走过第1~2个结点,才能得到第3个结点。
单链表查找算法思路:

  • 链表存在,输入要查找的值
  • 声明中间变量指向头结点,用于遍历链表
  • 循环
  • 指针后移遍历链表
  • 将链表中与查找值相等的数据返回
int SearchList(LinkList L,int elem)
{LinkList temp;temp = L;int position = 0;用于返回数据在链表中的位置while (temp->next){   position++;temp = temp->next;指针后移遍历链表if (elem == temp->data){printf_s("Searchdata=%d,postion=%d\n", temp->data, position);}return position;}return 0;
}

3.在单链表中,替换某一个位置的数据

单链表替换算法思路:

  • 链表存在,输入要替换的位置,要替换的数值
  • 声明中间变量指向头结点,用于遍历链表
  • 循环
  • 指针后移遍历链表,到要替换的位置,跳出循环
  • 将要替换的值,赋值到数据域
  • 返回链表的头结点
LinkList  ReplaceList(LinkList L,int pos,int elem)
{LinkList temp = L;temp = temp->next;指向开始结点(注意头结点与开始结点区别)头结点的后继结点为开始结点for (int i = 0; i < pos; i++){temp = temp->next;}temp->data = elem;return L;
}

4.在单链表中,某一个位置插入数据

单链表插入算法思路:

  • 链表存在,输入要插入的位置,要插入的数值
  • 声明中间变量指向头结点,用于遍历链表
  • 循环
  • 指针后移遍历链表,找到插入位置前的结点
  • 新建结点,将要插入的数据,赋值到新建结点的数据域
  • 返回链表的头结点
    在这里插入图片描述
LinkList InsertList(LinkList L,int pos,int elem)
{LinkList temp = L;int i = 0;temp = temp->next;指向开始结点for (i = 0; i < pos-1; i++){if ((temp == NULL) || (i > pos - 1)){printf("%s:Insert false!\n", __FUNCTION__);return L;}temp = temp->next;}LinkList new = (LinkList)malloc(sizeof(Node));new->data = elem;new->next = temp->next;新建结点指向插入的下个结点temp->next = new;插入位置的结点指针指向新建结点return L;}
第二种写法LinkList InsertList(LinkList L, int pos, int elem)
{LinkList temp = L;	//引入一个中间变量,用于循环变量链表int i = 0;/* 首先找到插入结点的上一结点,即第pos-1个结点 */while( (temp!=NULL)&&(i<pos-1) ){temp = temp->next;++i;}/* 错误处理:链表为空或插入位置不存在 */if( (temp==NULL)||(i>pos-1) )		{printf("%s:Insert false!\n",__FUNCTION__);return (LNode*)temp;}LinkList new = (LinkList)malloc(sizeof(Node));	//创建新结点newnew->data = elem;		插入的新结点的数据域new->next = temp->next; 新结点的next指针指向插入位置后的结点temp->next = new;		插入位置前的结点的next指针指向新结点return L;返回头结点

4.在单链表中,某一个位置删除数据

单链表插入算法思路:

  • 链表存在,输入要插入的位置,要插入的数值
  • 声明中间变量指向头结点,用于遍历链表
  • 循环
  • 指针后移遍历链表,找到插入位置前的结点
  • 新建结点,将要插入的数据,赋值到新建结点的数据域
  • 返回链表的头结点
    在这里插入图片描述
LinkList DeleteList(LinkList L, int pos, int *elem)
{LinkList temp = L;int i = 0;temp = temp->next;指向开始结点LinkList del;新建结点for (i = 0; i < pos - 1; i++){if ((temp == NULL) || (i > pos - 1)){printf("%s:Insert false!\n", __FUNCTION__);return L;}temp = temp->next;}del = temp->next; 结点指向被删除结点*elem = del->data; 结点数据域存储到elem中temp->next = del->next;要删除位置前的结点指向要删除结点后的结点free(del);释放内存del = NULL;防止野指针return L;}
第二种写法LinkList Delete(LinkList L, int pos, int *elem)
{LinkList temp = L;	//引入一个中间变量,用于循环变量链表int i = 0;/* 首先找到删除结点的上一结点,即第pos-1个结点 */while( (temp!=NULL)&&(i<pos-1) ){temp = temp->next;++i;}/* 错误处理:链表为空或删除位置不存在 */if( (temp==NULL)||(i>pos-1) ){printf("%s:Delete false!\n",__FUNCTION__);return temp;}LinkList del = temp->next;	//定义一个del指针指向被删除结点*elem = del->data;			//保存被删除的结点的数据域temp->next = del->next;		/*删除结点的上一个结点的指针域指向删除结点的下一个结点,也可写为“temp->next = temp->next->next”*/free(del);					//手动释放该结点,防止内存泄露del = NULL;					//防止出现野指针return L;			

在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部