大话数据结构---(二)线性表

1.线性表的定义

零个或多个数据元素的有限序列。这里强调“序列”,也就是说元素之间是有顺序的,若元素存在多个,则第一个元素无前驱元素,最后一个元素无后继元素,其余每个元素都有且只有一个前驱和后继。就好比间谍片里,为了安全起见,你只知道你的上一级的直属上司和你下一级的手下,你并不知道你的上司是谁的手下,也不知道你的手下是谁的上司。(反正就是脑子不够用)

2.线性表的顺序存储结构

既然线性表元素之间本来就是有顺序的,那么线性表的顺序存储结构又有什么意义呢?对了,在数据元素有序的前提下,再加上存储单元有序,换句话说,就是用一段地址连续的存储单元依次存储线性表的数据元素,如下图所示。
在这里插入图片描述 来看看线性表的顺序存储的结构代码:

  #define MAXSIZE 100//存储空间初始分配量
  typedef int ElemType;//ElemType类型根据实际情况而定,这里用int代替
  typedef struct{
  ElemType data[MAXSIZE];//数组存储数据元素,最大值为MAXSIZE
  int length;//线性表当前长度
}SqList;

注:这里强调几个概念
数组的长度:是存放线性表的存储空间的长度,存储分配后这个量一般是不变的。
线性表的长度:是线性表中数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。
So~在任意时刻,线性表的长度应该小于等于数组的长度。
小插曲:typedef struct
typedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。
具体区别在于:
若struct node{}这样来定义结构体的化。在申请node的变量时,需要这样写,struct node n;
若用typedef,可以这样写,typedef struct node{}NODE;。在申请变量时就可以这样写,NODE区别就在于使用时,是否可以省去struct这个关键字。

  • (1)获得元素操作
    在这里插入图片描述
  • (2)插入元素操作
    思路:1.如果插入位置不合理,抛出异常;
    2.如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;
    3.从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置;
    4.将要插入元素填入位置i处;
    5.表长加1,这里特别注意; 在这里插入图片描述 在这里插入图片描述
  • (3)删除元素操作
    思路:1.如果删除位置不合理,抛出异常;(这里很容易忽视)
    2.取出删除元素;
    3.从删除元素位置开始遍历到最后一个元素位置,分别将他们呢都向前移动一个位置;
    4.表长减1。 在这里插入图片描述在这里插入图片描述
  • (4)线性表顺序存储结构的优缺点
    优点:1.无须为表示表中元素之间的逻辑关系而增加额外的存储空间。
    2.可以快速地存取表中任意位置的元素。
    缺点:1.插入和删除操作需要移动大量元素。
    2.当线性表长度变化的较大时,难以确定存储空间的容量。
    3.造成存储空间的“碎片”。

3.线性表的链式存储结构

要想实现数据成线性关系,却又不是通过地址连续来访问下一个地址,那么就需要数据元素另外存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。这两部分信息组成数据元素的存储映像,称为结点。我们把链表中第一个结点的存储位置叫做头指针,n个结点链结成一个链表,即为线性表的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表在这里插入图片描述 有时为了方便对链表的操作,会在单链表的第一个结点前附设一个结点,称为头结点头结点的数据域可以不存储任何信息,也可以存储如线性表的长度等附加信息。
头指针与头结点的异同
头指针:(1)头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;
(2)头指针具有标识作用,所以常用头指针冠以链表名字;
(3)无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
头结点:(1)头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义;
(2)有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作域其他结点的操作就统一了;
(3)头结点不一定是链表必须要素。
单链表中,我们在C语言中可用结构指针来描述:

typedef struct Node{
ElemType data;
struct Node *next;
}Node,*LinkList;//定义LinkList
  • (1)单链表的读取
    思路:1.声明一个指针P指向链表第一个结点,初始化j从1开始;
    2.当j<i时,就遍历链表,让指针向后移动,不断指向下一个结点,j累加1;
    3.若到链表末尾P为空,则说明第i个结点不存在;
    4.否则查找成功,返回结点P的数据。 在这里插入图片描述
  • (2)单链表的插入与删除
    单链表第i个数据插入结点的算法思路:
    1.前三步同上;
    2.否则查找成功,在系统中生成一个空结点s;
    3.将数据元素e赋值给s->data;
    4.单链表的插入标准语句 s->next=p-next;p->next=s;
    5.返回成功。 在这里插入图片描述在这里插入图片描述
    单链表第i个数据删除结点的算法思路:
    1.前三步同上;
    2.否则查找成功,将欲删除的结点p->next赋值给q;
    3.单链表的删除标准语句p->next=q->next;
    4.将q结点中的数据赋值给e,作为返回;
    5.释放q结点;(这里很容易遗漏)
    6.返回成功。 在这里插入图片描述 在这里插入图片描述
  • (3)单链表的整表创建
    思路:1.声明一指针p和计数器变量i;
    2初始化一空链表L;
    3.让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
    4.循环:
    (1)生成一新结点赋值给p;
    (2)随机生成一数字赋值给p的数据域p->data;
    (3)将p插入到头结点与前一新结点之间; (头插法) 在这里插入图片描述 在这里插入图片描述 单链表结构与顺序存储结构优缺点:
    存储分配方式:1.顺序存储结构用一段连续的存储单元依次存储线性表的数据元素。
    2.单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素。
    时间性能:1.查找:顺序存储结构 O(1),单链表O(n)。
    2.插入和删除:顺序存储结构需要移动表长一半的元素,时间为O(n)。
    单链表在给出某位置的指针后,插入和删除时间仅为O(1)。
    空间分配:1.顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢。
    2.单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制。
  • (4)静态链表:用数组描述的链表叫做静态链表。可能会觉得数组和链表完全是两码事,但这里并非是链表结构,只是实现了链表相邻数据元素并不一定内存地址相邻的特点,用索引值代替next指针,所以这种描述方法还有起名叫做游标实现法。
    线性表的静态链表存储结构:
#define MAXSIZE 1000
typedef struct{
  ElemType data;
  int cur;//游标,为0时表示无指向
}Component,StaticLinkList[MAXSIZE];

在这里插入图片描述 静态链表的插入操作:解决的办法是将所有未被使用过的及被删除的分量用游标链成一个备用的链表,每当进行插入时,便可以从备用链表上取得第一个结点作为待插入的新结点

  //若备用空间链表非空,则返回分配的结点下标,否则返回0
  int Malloc_SLL(StaticLinkList space){
    int i=space[0].cur;//当前数组第一个元素的cur存的值
    //就是要返回的第一个备用空闲的下标
    if(space[0].cur)
    space[0].cur=space[i].cur;//由于要拿出一个分量来使用了,所以我们就得把它的下一个分量用来做备用
    return i;
}

注:总的来说,静态链表其实是为了给没有指针的高级语言设计的一种实现单链表能力的方法。尽管大家不一定会用得上,但这样的思考方式是非常巧妙的,应该理解其思想,这里就不详细介绍静态链表的其它用法了。感觉用的不多

  • (5)循环链表:如果单链表掌握的话,循环链表理解起来也不难。将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为但循环链表,简称循环链表。
    在这里插入图片描述
  • (6)双向链表:双向链表时在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。
    线性表的双向链表存储结构:
typedef struct DulNode{
ElemType data;
struct DulNode *prior;//直接前驱指针
struct DulNode *next;//直接后继指针
}DulNode,*DulLinkList;

在这里插入图片描述双向链表的删除操作:p->prior->next=p->next;
p->next->prior=p->prior;
free§; 在这里插入图片描述双向链表的插入操作:s->prior=p;
s->next=p->next;
p->next->prior=s;
p->next=s;
在这里插入图片描述

发布了7 篇原创文章 · 获赞 7 · 访问量 350

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/104983930
今日推荐