【数据结构】线性表

线性表

  • 线性表定义
  • 线性表基本操作
  • 线性表的物理表示
    • 顺序表
    • 单链表
    • 双链表
    • 循环链表
    • 静态链表
  • 顺序表与链表的比较
    • 存取方式
    • 逻辑结构与物理结构
    • 查找、插入与删除
    • 空间分配
  • 怎样选取存储结构
    • 基于存储
    • 基于运算
    • 基于环境


线性表定义

  • 线性表是具有相同数据类型的 n n n 个数据元素的有限序列,其中 n n n 为表长。当 n = 0 n=0 n=0 时线性表是一个空表。
  • 若用 L L L 命名线性表,表示为: L = ( a 1 , a 2 , a i , a i + 1 , . . . , a n ) L=(a_1, a_2, a_i, a_{i+1}, ... , a_n) L=(a1,a2,ai,ai+1,...,an)
    • a 1 a_1 a1 是第一个元素,称为==“表头元素”==;
    • a n a_n an 是最后一个元素,称为==“表尾元素”==;
    • 除第一个元素外,每个元素有且只有一个直接前驱
    • 除最后一个元素外,每个元素有且只有一个直接后继
  • 线性表的逻辑具有顺序性,表中元素有其先后次序。
  • 线性表的数据类型都相同,每个元素占有相同大小的存储空间

线性表基本操作

线性表的主要操作如下:

InitList(&L)	 	// 初始化表,构造一个空的线性表
Length(L)			// 求表长,返回线性表L的长度,即线性表中元素个数
LocateElem(L,e)		// 按值查找操作,在表L中查找值e
GetElem(L,i)		// 按位查找操作,获取表L中第i个位置的元素的值
ListInsert(&L,i,e)	// 插入操作,在表L中的第i个位置插入指定元素e
ListDelete(&L,i,&e)	// 删除操作,删除表L中第i个位置元素并用e返回删除元素的值
PrintList(L)		// 输出操作,按前后顺序输出线性表L的所有元素的值
Empty(L)			// 判空操作,若L为空表返回True,否则False
DestoryList(&L)		// 销毁操作,销毁线性表,并释放线性表L占用的内存空间

线性表的物理表示

【数据结构】线性表_第1张图片

  • 顺序表,逻辑上相邻的两个元素在物理位置上也相邻;
  • 链式表示,通过“链”建立起数据元素之间的逻辑关系。

顺序表

  • 线性表的顺序表示,逻辑上相邻的两个元素在物理位置上也相邻;
  • 顺序表的任一元素的存取时间复杂度为 O ( 1 ) O(1) O(1)
  • 顺序表的插入、删除操作所需时间复杂度为 O ( n ) O(n) O(n),因为要保证物理位置的相邻,所以插入和删除都需要移动大量元素,时间也都耗费在移动中;
  • 顺序表详细博文链接:https://xu-hongduo.blog.csdn.net/article/details/133883937

单链表

  • 单链表无需顺序表那样必须占用相邻的物理空间存储,而是采用链的方式连接;
  • 单链表的任一元素的存取时间复杂度为 O ( 1 ) O(1) O(1)
  • 单链表的插入、删除操作所需时间复杂度为 O ( n ) O(n) O(n),因为物理位置不相邻,所以要耗费时间遍历查找要删除、插入元素的前驱元素。
  • 单链表详细博文链接:https://xu-hongduo.blog.csdn.net/article/details/133884286

双链表

  • 双链表在单链表的基础上,在每个元素上都加入第二个指针,前驱指针。如此以来,在得知待插入和删除元素的物理地址时,插入和删除操作的时间复杂度降低为 O ( 1 ) O(1) O(1),因为无需再耗费时间再次从头遍历来查找要删除、插入元素的前驱元素。
  • 双链表详细博文链接:https://xu-hongduo.blog.csdn.net/article/details/133885829

循环链表

  • 循环链表分为循环单链表以及循环双链表;

循环单链表:

  • 循环单链表中最后一个结点的指针不是 NULL,而改为指向头结点。从而整个链表形成一个环。
  • 循环单链表判空的条件为表尾结点指针是否指向头结点;
  • 循环单链表因为是一个“环”,所以在任何一个位置上的插入和删除操作都是等价的,循环单链表可以从表中的任意一个结点开始遍历整个列表。

循环双链表:

  • 循环双链表中,头结点的 p r i o r prior prior 指针指向表尾结点,尾结点的 n e x t next next 指针指向头结点。
  • 在循环双链表 L L L 中,某结点 ∗ p *p p 为尾结点时,p->next==L;当循环双链表为空表时,其头结点的 p r i o r prior prior 域和 n e x t next next 域都等于 L L L

静态链表

  • 静态链表借助数组来描述线性表的链式存储结构,结点也有数据域 d a t a data data 和指针域 n e x t next next。而与单链表不同的是,这里的指针是结点的相对地址。所谓相对地址请读者联系下张图理解;

  • 【数据结构】线性表_第2张图片

  • 其中 a a a 的直接后继为 b b b,所以在表 “静态链表示例” 中, a a a 的直接后继的物理地址为 1 1 1,查找表中代表的物理地址为 1 1 1 的元素,为 b b b

#define MaxSize 50		// 静态链表最大长度
typedef struct{			// 静态链表结构类型的定义
	ElemType data;		// 存储数据元素
	int next;			// 下一个元素的数组下标
}SLinkList[MaxSize];
  • 静态链表以 n e x t = = − 1 next==-1 next==1 作为其结束的标志。静态链表的插入、删除操作与动态链表相同,只需要修改指针而无需移动元素。
  • 总而言之,静态链表没有单链表使用起来方便,但是在一些不支持指针的高级语言中,这是一种非常巧妙的设计方法。

顺序表与链表的比较

存取方式

  • 顺序表:可以顺序存取、也可随机存取;因为顺序表逻辑上相邻的元素物理地址上也相邻;
  • 链表:只能从表头顺序存取元素,因为链表不具有物理地址的连续性。无论是单链表还是双链表;

逻辑结构与物理结构

  • 顺序存储:逻辑结构上相邻的元素,物理存储位置也相邻;
  • 链式存储:逻辑上相邻的元素,物理存储位置不一定相邻,对应的逻辑关系通过链接来实现;

查找、插入与删除

  • 顺序表:按值查找 O ( n ) O(n) O(n),按序号查找 O ( 1 ) O(1) O(1),插入删除 O ( n ) O(n) O(n)
  • 链表:皆为 O ( n ) O(n) O(n)

空间分配

  • 顺序表:静态存储下存储空间满溢出,动态存储下,另外开辟新的连续空间,需要移动大量元素,对空间比较浪费;
  • 链表:有地方就能塞,灵活高效;

怎样选取存储结构

基于存储

当线性表的长度难以估计时,不宜采取顺序表;反之;

基于运算

如果经常做的运算是按序号访问数据元素,无疑顺序表优于链表;
在进行插入、删除操作时,平均移动表中一半的元素。当数据元素的信息量较大时,应考虑链表优先。虽然链表也需要找插入位置,但是其主要操作是对比,而不是移动。

基于环境

显而易见的是,顺序表的结构设计上明显更为实现起来较链表更为简单。
总而言之,较稳定的线性表选择顺序表,涉及频繁操作的选择链式存储。


以上

你可能感兴趣的:(计算机基础知识,数据结构)