文章目录
1.1 线性表的基本概念
1、线性表的定义
线性表是具有相同特征数据元素的一个有限序列。该序列中的所含元素的个数即为线性表的长度(n,n>=0)。可以是一个空表
线性表是一种简单的数据结构,以一队学生为例,人数相当于线性表的长度;人数是有限的,对应线性表的有限性;组中的人都是学生,体现了线性表元素的相同特征;线性表可以是有序的,也可以是无序的。
2、线性表的逻辑特征
线性表只有一个表头元素,只有一个表尾元素,表头元素没有前驱,表尾元素没有后继,除了表头表尾之外,其他元素只有一个直接前驱和一个直接后继。
以学生为例,表头和表尾相当于站在队头和队尾的学生,分别只有一位;站在队头的学生前面没有学生,也就是没有前驱;站在队尾的学生后面没有人,也就是没有后继;中间的学生,紧挨着他的前面一个学生和后面一个学生都只有一位,也就是只有一个直接前驱和一个直接后继。
3、线性表的存储结构
线性表的存储结构有顺序存储结构和链式存储结构两种,前者为顺序表,后者为链表。
(1) 顺序表(array-based list)
顺序表就是将线性表中的所有元素按照逻辑顺序,依次存储到从指定的存储位置开始的一块连续的存储空间中。
顺序表的实现是用数组来存储表中的元素,一开始要分配固定长度的数组。而且数组的位置与线性表元素的位置相对应,表中的第i个元素存储在数组的第i个单元中。
顺序表对表中任意一个元素的随机访问相当容易,给出一个位置即可直接获取该位置的元素值,只需要花费**O(1)的时间。而插入和删除则需要花费O(n)**的时间。
(2) 链表(linked list)
链表是利用指针实现线性表,它能够按照需要为表中新的元素分配存储空间,是动态的,且不支持随机访问。
链表由一系列叫作表的结点**(node)的对象组成,每个结点不仅包含所存元素的信息还包含元素之间逻辑关系的信息**,如单链表中前驱结点包含后继结点的地址信息。链表的结点可以散落在内存的任意位置。建立结点类还有一个好处就是它能够被栈和队列的链接实现方式重用。
在链表中插入元素无需移动元素。
链表有以下五种形式:
1)单链表
在每个结点中除了包含数据域外还包含一个指针域,用以指向其后继结点。单链表还分为带头结点的单链表和不带头结点的单链表。
-
带头结点的单链表中,头指针head指向头结点,头结点的值域不包含任何信息,从头结点的后继结点开始存储信息。头指针时钟不为NULL,
head.next
等于NULL的时候,链表则为空。如下图所示: -
不带头结点的单链表中的头指针head直接指向开始结点,即上图的结点A1,当head等于NULL时,链表为空。
头结点的引入方便我们进行插入和删除操作。
ps:注意区分头指针与头结点
头指针:指向链表中的第一个结点,即head指针
尾指针:指向链表中的最后一个结点,即tail指针
头结点:带头结点的链表中的第一个结点,只作为链表存在的标志
2)双链表
双链表即在单链表的基础上增加了一个指针域,指向当前结点的前驱,这样可以方便地由其后继来找到其前驱,从而实现输出终端结点到开始结点的数据序列。
双链表也区分带头结点与不带头结点,上图为带头结点的双链表
3)循环链表
有些应用不需要线性表中有明显的头尾元素,这时候就可以利用循环链表。将链表中最后一个元素的next域中存储为指向线性表中第一个元素的指针,就构成了一个循环链表。在这种实现方式下就不需要尾指针tail了。
没有尾指针可能会使链表的操作陷入死循环,但是也可以利用head指针标记表的处理操作是否周游了整个表。
带头结点的循环单链表如下:
带头结点的循环双链表如下:
4)静态链表
静态链表借助一维数组来表示,如下图所示
4、顺序表与链表的比较
(1) 空间比较
1)存储方式的比较
顺序表的存储空间时一次性分配的,链表的存储空间是多次分配的
2)存储密度
存储密度=结点值域所占的存储量/结点结构所占的存储总量
顺序表=1;链表<1(存在指针域)
(2) 时间比较
1)存取方式
顺序表可以随机存取也可以顺序存取;链表只能顺序存取。所谓顺序存取,以读取为例,要读取某个元素必须遍历其之前的所有元素才能找到它)
2)插入删除时移动的元素个数
顺序表平均需要移动近一半元素;链表不需要移动元素,只需要修改指针
对于具有n个元素的顺序表,插入一个元素所需要的平均移动个数为多少?
1、有n+1个插入位置,概率都为p=1/(n+1)
2、假设将新元素插入在表中第i个元素之后,则需要将第i个元素之后的所有元素都往后移动一个位置,总移动个数为n-i
3、结合12,可知移动元素个数的数学期望为E=n/2
同理,删除一个元素所需要的平均移动个数为(n-1)/2
所以对于顺序表,插入和删除算法的平均时间复杂度为O(n)