数据结构 - 线性表链式存储结构

链式存储

链式存储 :用一组任意的存储单元存储线性表中的数据元素。用这种方法存储的线性表简称线性链表。

存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的。

链表中结点的逻辑顺序和物理顺序不一定相同。(即不要求逻辑上相邻的元素在物理位置上也相邻)

为了正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其直接后继结点的地址(或位置),称为指针(pointer)或链(link),这两部分组成了数据元素ai的存储映像

链表是通过每个结点的指针域将线性表的n个结点按其逻辑次序链接在一起的。

每一个结点只包含一个指针域的链表,称为单链表。

为操作方便,总是在链表的第一个结点之前附设一个头结点(头指针)head指向第一个结点(即头结点的指针域存放第一个结点的存储位置)。头结点的数据域可以不存储任何信息(或链表长度等信息)。

因为最后一个数据元素没有直接后继,所以线性链表中最后一个结点的指针为空(NULL)。

为操作方便,总是在链表的第一个结点之前附设一个头结点(头指针)head指向第一个结点(即头结点的指针域存放第一个结点的存储位置)。头结点的数据域可以不存储任何信息(或链表长度等信息)。

因为最后一个数据元素没有直接后继,所以线性链表中最后一个结点的指针为空(NULL)。

结点的描述与实现

  C语言中用带指针的结构体类型来描述
typedef  struct  Lnode
{   ElemType  data;     /*数据域,保存结点的值 */
struct   Lnode  *next;      /*指针域,类型是struct   Lnode */
}LNode, *LinkList;        /*结点的类型名 */
LNode,结点结构;LinkList:链表结构
 //LinkList L;L为单链表名,同时也可作为表的头指针名,指向表中第一个结点,即L的指针域存储第一个结点的地址。
 //若L为空,则表示线性表为空表,其长度为0.

结点的实现

结点是通过动态分配和释放来的实现,即需要时分配,不需要时释放。实现时是分别使用C语言提供的标准函数:malloc() ,realloc(),sizeof() ,free() 。

动态分配 p=(LNode*)malloc(sizeof(LNode));

函数malloc分配了一个类型为LNode的结点变量的空间,并将其首地址放入指针变量p中。

动态释放 free(p) ;

系统回收由指针变量p所指向的内存区。p必须是最近一次调用malloc函数时的返回值。

算法描述
LNode  *create_LinkList(void)
    /*  头插入法创建单链表,链表的头结点head作为返回值  */
{    int data ;
LNode *head, *p;
head= (LNode  *) malloc( sizeof(LNode));
head->next=NULL;     /*  创建链表的表头结点head  */
while (1) //一直执行
{   scanf(“%d”, &data) ;
if (data==32767)  break ;
p= (LNode  *)malloc(sizeof(LNode));
p->data=data;     /*  数据域赋值  */
p->next=head->next ;  head->next=p ;
       /*  钩链,新创建的结点总是作为第一个结点  */
}
return (head);
}
    // 返回值是表头结点head,实际就是所创建的链表。此时主函数中只要建一个LNode *类型的变量,即可调用该函数。如
 LNode   *head;  或者LinkList  head;
 head=create_LinkList();

尾插入法建表

头插入法建立链表虽然算法简单,但生成的链表中结点的次序和输入的顺序相反。若希望二者次序一致,可采用尾插法建表。

该方法是将新结点插入到当前链表的表尾,使其成为当前链表的尾结点。

算法描述
LNode  *create_LinkList(void)
     /*  尾插入法创建单链表,链表的头结点head作为返回值  */
{   int data ;
LNode *head, *p, *q;
head=p=(LNode  *)malloc(sizeof(LNode));
p->next=NULL;        /*  创建单链表的表头结点head  */
while (1)
{    scanf(“%d”,& data);
if (data==32767)  break ;
q= (LNode  *)malloc(sizeof(LNode));
q->data=data;     /*   数据域赋值  */
q->next=p->next;  p->next=q; p=q ;
 /*钩链,新创建的结点总是作为最后一个结点*/
}
return (head);
}
     无论是哪种插入方法,如果要插入建立单链表的结点是n个,算法的时间复杂度均为O(n)。
对于单链表,无论是哪种操作,只要涉及到钩链(或重新钩链),如果没有明确给出直接后继,钩链(或重新钩链)的次序必须是“先右后左”,否则就会丢掉链表中的一些结点。

单链表的查找

(1) 按序号查找 取单链表中的第i个元素。

对于单链表,不能象顺序表中那样直接按序号i访问结点,而只能从链表的头结点出发,沿链域next逐个结点往下搜索,直到搜索到第i个结点为止。因此,链表不是随机存取结构。

设单链表的长度为n,要查找表中第i个结点,仅当1≦i≦n时,i的值是合法的。

算法思想如下:

 从头结点开始顺链扫描,用指针p指向当前扫描到的结点,用j作统计已扫描结点数的计数器,当p扫描下一个结点时,j自动加1。

 P的初值指向头结点,j的初值为1。当j=i时,指针p所指的结点就是第i个结点。
算法描述
ElemType   Get_Elem(LNode *L , int  i)
{    int j ;   LNode *p;
p=L->next;  j=1;      /*  使p指向第一个结点  */
while  (p!=NULL && j<i)
{   p=p–>next;  j++;  }        /*  移动指针p , j计数  */
if  ( !p|| j>i)  return(ERROR) ;
 /*   p为NULL 表示i>n;  j>i表示i=0  */
 else      return(p->data);
}
移动指针p的频度:
i=0时:0次; i∈[1,n]:i-1次;i>n:n次。
∴时间复杂度: O(n)。

按值查找

按值查找是在链表中,查找是否有结点值等于给定值key的结点? 若有,则返回首次找到的值为key的结点的存储位置;否则返回NULL。查找时从开始结点出发,沿链表逐个将结点的值和给定值key作比较。

算法描述
LNode *Locate_Node(LNode *L,int key)
/*  在以L为头结点的单链表中查找值为key的第一个结点  */
{   LNode *p=L->next;
while  ( p!=NULL&& p->data!=key)
          p=p–>next;
if  (p->data==key)   return p;
else
{    printf(“所要查找的结点不存在!!\n”);
retutn(NULL); }
}
算法的执行与形参key有关,平均时间复杂度为O(n)。
时间: 2024-10-13 14:12:17

数据结构 - 线性表链式存储结构的相关文章

线性表链式存储结构的c语言实现

线性表链式存储结构的c语言实现的操作 <1>定义链式存储结构的结点. <2>初始化线性表 <3>判定是否为空 <4>清空列表 <5>返回L中数据元素个数 <6>用e返回L中第i个数据元素的值 <7>返回L中第1个与e满足关系的数据元素的位序,若没有则返回0 <8>在L中第i个位置之前插入新的数据元素e,L的长度加1 <9>删除L的第i个数据元素,并用e返回其值,L的长度减1 <10>依次

【C语言--数据结构】线性表链式存储结构

直接贴代码 头文件 #ifndef __LINKLIST_H__ #define __LINKLIST_H__ typedef void LinkList; typedef struct _tag_LinkListNode { LinkList* next; }LinkListNode; LinkList* LinkList_create(); void LinkList_Destroy(LinkList* pstList); void LinkList_Clear(LinkList* pstL

线性表链式存储结构

链式存储 :用一组任意的存储单元存储线性表中的数据元素.用这种方法存储的线性表简称线性链表.存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的. 为了正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其直接后继结点的地址(或位置),称为指针(pointer)或链(link),这两部分 组成了链表中的结点结构,如下图所示. data :数据域,存放结点的值.next :指针域,存放结点的直接后继的地址. 指针域和数据域组成数据元素称

数据结构与算法——线性表链式存储结构(静态链表)

今天总结静态链表. 什么是静态链表? 我理解静态链表是一种伪链表,因为它没有使用指针.静态链表使用数组实现的,这个数组是一个结构体数组,结构体由数据域和指针域构成,与单链表不同的是,这个指针域并不是指针,而是一个整数,用来指向下一个结点(数组下标). 静态链表中实际上相当于有两个链表,一个时实际数据所构成的一个链表,另一个是数组中空元素所构成的链表,称为空闲链表或备用链表,用来存放插入进来的元素. 心得:静态链表感觉比单链表,双向链表绕很多,看书的时候,书上在释放结点空间那块写的很复杂,后来和我

线性表链式存储的实现详解

本文原创,转载请注明:http://blog.csdn.net/j903829182/article/details/38173681 #include<stdio.h> #include<malloc.h> //线性表的链式存储和实现,带头点 #define true 1 #define false 0 typedef int DataType;//定义抽象数据类型 //节点的结构体 typedef struct Node{ DataType data;//节点的数据域 stru

线性表链式存储的基本操作

线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任意元素.线性表链式存储结构特点是用一组任意的存储单元存储数据元素,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储本身信息外,还要存储指示其直接后继的信息(即直接后继的存储位置).这两部分信息称为数据元素ai的存储映像,称为结点(node).它包括两个域,其中存储数据信息的称为数据域,存储直接后继存储位置的域称为指针域. 1.线性表的单链表存储结构 typ

浅谈数据结构之线性表链式存储(二)

前面我们所讲的线性表的顺序存储结构,它是有优缺点,最大的缺点是插入与删除时需移动大量的元素,这显然需要耗费许多时间.这时,我们就引入线性表的链式存储结构,它的特点是:用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的.这就意味着,这些数据可以存在内存中未被占用的任意位置上,即当线性表进行插入与删除时就不需要移动大量的元素了,节约了时间. 链式结构中,除了需要存储数据元素的信息外,还要存储它的后继元素的存储地址.我们把存储数据元素信息的域称为数据域,把存储直接后继

数据结构与算法——线性表链式存储(单链表)

今天总结单链表的实现. 什么是链表? 就是采去链式存储结构的线性表,所谓链式存储就好比火车的车厢一样,一节一节的连接起来,成为一个线性表.这种方式采用动态存储分配方式,即程序在运行时根据实际需要申请内存空间,不需要时将内存空间释放掉. 链表用一组任意的存储单元存放线性表中的各个元素,这组存储单元可以是连续的,也可以是不连续的. 什么是单链表? 单链表简单理解就是单向的,就像火车一样.如果将火车头与火车为连接在一块,就构成了循环链表. 链表的结构:链表采用节点结构,这个节点分为两部分,一部分存储数

数据结构(一)线性表链式存储实现

(一)前提 在前面的线性表顺序存储结构,最大的缺点是插入和删除需要移动大量的元素,需要耗费较多的时间.原因:在相邻两个元素的存储位置也具有邻居关系,他们在内存中的位置是紧挨着的,中间没有间隙,当然无法快速插入和删除.为了解决这个为题,出现了链式存储结构 (二)链式线性表两种结构(带有头结点和不带头结点) 不带头结点: 空链表: 带有头结点: 空链表: (三)头结点和头指针的区别 头指针: 1.头指针是指向第一个结点的指针,若是链表中只有头结点,则是指向头结点的指针 2.头指针具有标识作用,所以常