线性表
线性表(Linear List)是最简单和最常用的一种数据结构,它是由n个数据元素(节点)a1,a2,a3,...an
组成的有限序列,数据元素的个数n
为表的长度。
线性表的逻辑特征(非空的线性表)
- 有且只有一个称谓开始元素的
a1
, 他没有前趋,仅有一个直接后继a2
- 有且只有一个称为终端元素的
an
,他没有后继,仅有一个直接前趋an-1
- 其余元素
ai
(2 <= i <= n-1 )称为内部元素,它们都有一个直接前趋ai-1
和后继ai+1
- 有且只有一个称谓开始元素的
- 线性表的基本运算
- 置空表
initList(L)
,构造一个空的表 - 求表长 “`ListLength(L)
- 取表中的第
i
个元素GetnNode(L, i)
- 按值查找
LocateNode(L, x)
, 在表L中查找一个值为i的元素 - 插入
InsertList(L, i, x)
, 在表L的第i个元素插入一个值为x的元素,表的长度加1 - 删除
DeleteList(L, i)
, 删除表L的第i个元素,表长减一
- 置空表
顺序表
线性表的顺序存储指的是将线性表的数据元素按照逻辑顺序依次存入一组地址连续的存储单元里,用这种方法存贮的线性表称为顺序表。
线性表的第i个元素的存储位置:
// d为每个元素占用的存储单元个数
LOC(ai) = LOC(a1) + (i - 1) * d
线性表的这种机内表示称为线性表的顺秀存储结构,它的特点是,元素在表中的相邻关系,在计算机内也存在着相邻的关系。每个元素a1
的存储地址是该元素
在表中的位置i的线性函数,只要知道基地址和每个元素占用的单元数(元素的大小),就可以求出表中的任意元素的存储地址。
只要确定了线性表存储的起始位置,线性表中的任意一个元素都可以随机存取,所以顺序表也是一种随机存取结构。
优点
- 通过下标获取元素,时间复杂度为O(1)
- 缺点
- 插入,删除操作需要移动大量元素,时间复杂度为O(n)
链表
线性表顺序存储结构的特点是,在逻辑关系上相邻的两个元素在存储位置上也是相邻的,因此可以随机存取表中的任一元素。
但是,当经常需要做插入和删除运算时,需要移动大量的元素,而采用链式存储结构时就可以避免这些移动。
由于链式存储结构存储线性表的数据元素的存储位置可能是连续的也可能是不连续的,因此链表的节点是不可以随机存取的。
在使用链式存储结构表示每个数据元素ai
是,除了存储ai
本身的信息之外,还需要一个存储指示其后继元素ai+1
存储位置的指针,由这两个部分组成元素ai
的存储映像通常称为节点。
- 节点包括两个域:
- 存储数据元素的域,称为数据域
- 存储直接后继指针的域,称为指针域
利用这种存储方式表示的线性表称为链表:
+-----------+------------+
| data | next |
+-----------+------------+
链表指的是有n个节点链成一个链表,即为线性表的链式存储结构
单链表
单链表的每个节点只包含一个指针域,因此称为单链表。
head
|
| +----+---+ +----+----+ +----+----+
\----> | a1 | |----->| a2 | |----> ... ---->| an | |
+----+---+ +----+----+ +----+----+
数据结构
线性表
线性表(Linear List)是最简单和最常用的一种数据结构,它是由n个数据元素(节点)a1,a2,a3,...an
组成的有限序列,数据元素的个数n
为表的长度。
线性表的逻辑特征(非空的线性表)
- 有且只有一个称谓开始元素的
a1
, 他没有前趋,仅有一个直接后继a2
- 有且只有一个称为终端元素的
an
,他没有后继,仅有一个直接前趋an-1
- 其余元素
ai
(2 <= i <= n-1 )称为内部元素,它们都有一个直接前趋ai-1
和后继ai+1
- 有且只有一个称谓开始元素的
- 线性表的基本运算
- 置空表
initList(L)
,构造一个空的表 - 求表长 “`ListLength(L)
- 取表中的第
i
个元素GetnNode(L, i)
- 按值查找
LocateNode(L, x)
, 在表L中查找一个值为i的元素 - 插入
InsertList(L, i, x)
, 在表L的第i个元素插入一个值为x的元素,表的长度加1 - 删除
DeleteList(L, i)
, 删除表L的第i个元素,表长减一
- 置空表
顺序表
线性表的顺序存储指的是将线性表的数据元素按照逻辑顺序依次存入一组地址连续的存储单元里,用这种方法存贮的线性表称为顺序表。
线性表的第i个元素的存储位置:
// d为每个元素占用的存储单元个数
LOC(ai) = LOC(a1) + (i - 1) * d
线性表的这种机内表示称为线性表的顺秀存储结构,它的特点是,元素在表中的相邻关系,在计算机内也存在着相邻的关系。每个元素a1
的存储地址是该元素
在表中的位置i的线性函数,只要知道基地址和每个元素占用的单元数(元素的大小),就可以求出表中的任意元素的存储地址。
只要确定了线性表存储的起始位置,线性表中的任意一个元素都可以随机存取,所以顺序表也是一种随机存取结构。
优点
- 通过下标获取元素,时间复杂度为O(1)
- 缺点
- 插入,删除操作需要移动大量元素,时间复杂度为O(n)
链表
线性表顺序存储结构的特点是,在逻辑关系上相邻的两个元素在存储位置上也是相邻的,因此可以随机存取表中的任一元素。
但是,当经常需要做插入和删除运算时,需要移动大量的元素,而采用链式存储结构时就可以避免这些移动。
由于链式存储结构存储线性表的数据元素的存储位置可能是连续的也可能是不连续的,因此链表的节点是不可以随机存取的。
在使用链式存储结构表示每个数据元素ai
是,除了存储ai
本身的信息之外,还需要一个存储指示其后继元素ai+1
存储位置的指针,由这两个部分组成元素ai
的存储映像通常称为节点。
- 节点包括两个域:
- 存储数据元素的域,称为数据域
- 存储直接后继指针的域,称为指针域
利用这种存储方式表示的线性表称为链表:
+-----------+------------+
| data | next |
+-----------+------------+
链表指的是有n个节点链成一个链表,即为线性表的链式存储结构
单链表
单链表的每个节点只包含一个指针域,因此称为单链表。
head
|
| +----+---+ +----+----+ +----+----+
\----> | a1 | |----->| a2 | |----> ... ---->| an | |
+----+---+ +----+----+ +----+----+
单链表中的每个节点的存储结构是存放在其直接前趋节点的指针域(next)中,而开始节点无直接前趋,因此设立头指着鞥heead只向开始节点。又由于终端节点无后继节点,所以终端节点的指针域为空
如果链表中一个节点都没有,则为空链表,此时head=NULL
。
- 基本运算
- 建立单链表
- 头插法:将节点插入到表头,节点的次序和输入的次序相反,将head指向新节点(p),将p的next指向原来head指向的节点
- 尾插法: 节点的次序与输入的次序一致,将新节点(p)插入在当前链表的表尾上,需要设立一个尾指针(rear),使其始终指向链表的尾节点
- 查找
- 在单链表中,任何两个节点的存储位置之间没有的联系,每个节点的存储位置包含在其前趋的指针域中,因此在单链表中存取第i个节点时,必须从表头节点开始搜索,平均复杂度为
O(n)
- 插入
- 先使新节点p指向ai-1的位置,然后生成一个数据域为x的新节点*s, 在进行插入操作,链表插入不需要移动节点,但是需要从表头开始进行查找,因此该操作的复杂度为
O(n)
- 删除
- 将链表的第i个元素从表中删除,由于第
i-1
个节点的存储地址是存储在第i-1个节点的指针域next中,因此要先使p指向第i-1个节点,然后使得p->next指向第i+1个节点,在将第i个节点释放掉。时间复杂度也是O(n)
- 建立单链表
循环链表
循环链表是链式存储结构的另一种形式,其特点是单链表中最后一个节点的指针域不为空,而是指向链表的头结点,使整个链表构成一个环。
任意一节点开始都可以访问表中的其他元素。这种结构形式的链表称为单循环链表。
循环链表的节点类型与单链表完全相同,在操作上也与单链表基本一致,差别仅在与算法中循环的结束判断条件不在是p或p->next是否为空,而是它们是否等于头结点。
双向链表
在单链表和单循环链表中的节点只设有一个纸箱器直接后继的指针域,因此从某个节点出发只能顺指针向后访问其他节点。若需要查找节点的直接前趋,则需要从头指针开始查找某节点的直接前趋节点。
双向链表可以从表中快速确定一个节点的直接前趋,双向链表中的节点类型中增加了一个指向其直接前趋的指针域prior
,形成了两条不同方向的链,因此称为双向链表。
与单链表不同的是在双向链表中插入和删除必须同时修改两个方向上的指针
顺序表和链表的比较
线性表有两种存储结构:顺序存储和线性存储,这两种存储表示各有其特点:顺序表结构可以随机存取表中的任一元素,元素的存储位置可用一个简单的公式来表示,然而在做插入和删除操作时,需要移动大量的元素。
链式存储则可以克服在做插入和删除运算时大量移动元素的问题,但却失去了随机存取的特点。
性能比较:
时间性能
- 在实际问题中,对线性表的经常性操作的查找运算,以顺序表形式存储为宜。顺序表是一种随机存取结构,可以随机访问任一节点,访问每个节点的时间代价是一样的,每个节点的存取时间复杂度均为O(1)。而链式存储结构必须从表头开始沿
链逐一访问节点,其时间复杂度为O(n)。 - 如果经常使用插入和删除操作,以链式存储结构为宜。因为顺序存储结构需要移动大量的节点元素,而链式存储结构只要修改相应的指针。
- 在实际问题中,对线性表的经常性操作的查找运算,以顺序表形式存储为宜。顺序表是一种随机存取结构,可以随机访问任一节点,访问每个节点的时间代价是一样的,每个节点的存取时间复杂度均为O(1)。而链式存储结构必须从表头开始沿
- 空间性能
- 顺序表的存储空间是静态分配的,在程序执行之前必须给定空间大小。若线性表的长度变化较大,则存储空间很难预先确定,设置过大则导致空间浪费,过小则导致空间溢出,因此对数据量大小能事先知道的问题,适合使用顺序存储结构。
- 链式存储结构是动态分配存储空间,只要内存有空闲的空间,就不会产生溢出,依次对数据量变化较大的动态问题,以链式存储结构为好。
线性表节点的存储密度,也是选择存储结构的一个重要依据,所谓存储密度就是节点空间的利用率。它的计算公式为:
存储密度 = (节点数据域所占空间)/ (整个节点所占空间)
一般来说存储密度越大,存储空间的利用率就越高。顺序表的存储密度为1,而链表的节点的存储密度小于1,若不考虑顺序表的空闲区,则顺序表的存储空间利用率为100%,远高于链表的节点存储密度。