线性表
1. 定义:是由n(n≧0)个数据元素(结点)a1,a2, …an组成的有限序列
◆ 当n=0时,称为空表
◆ 当n>0时,将非空的线性表记作: (a1,a2,…an)
◆ a1称为线性表的首结点,an称为线性表的尾结点
2 基本特点:数据元素是有序且是有限的
3. 性质:
◆ 除第一个元素外,每个元素均有唯一一个直接前驱
◆ 除最后一个元素外,每个元素均有唯一一个直接后继
◆ 所有结点具有相同的数据类型
* 注意,“前驱”、“后继”和“直接**”的区别 —— a1,a2,…ai-1都是ai(2≦i≦n)的前驱,但直接前驱只有一个
线性表——顺序存储
1. 顺序存储 :把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。用这种方法存储的线性表简称顺序表。
2. 特点:
◆ 线性表的逻辑顺序与物理顺序一致;
◆ 数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现
3. 位置的计算:
线性表的第i个数据元素ai的存储位置为:
LOC(ai)=LOC(a1)+(i-1)*l 【l 是每个元素要占用的空间】
4. 插入+删除:
顺序表上做插入、删除运算,平均要移动表上一半结点。当表长n较大时,算法的效率相当低。因此算法的平均时间复杂度为O(n)
具体的移动次数取决于——表长n和位置i
5. 查找定位删除:
◆ 比较的平均次数:
(n+1)/2
◆ 删除时平均移动次数:
(n-1)/2
平均时间复杂度:O(n) = (n-1)/2 +(n+1)/2
6. 结构体定义
typedef struct SqList{ ElemType Elem_array[MAX_SIZE]; int length; }SqList;
线性表——链式存储
1. 链式存储:用一组任意的存储单元存储线性表中的数据元素。用这种方法存储的线性表简称线性链表。
特点:
◆ 链表是通过每个结点的指针域将线性表的n个结点按其逻辑次序链接的
◆ 在每一个结点只包含一个指针域的链表,称为单链表
2.动态地建立单链表的方法:
(1)头插入法:
从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头上,直到读入结束标志为止。即每次插入的结点都作为链表的第一个结点。生成的链表中结点的次序和输入的顺序相反
(2)尾插入法:
将新结点插入到当前链表的表尾,使其成为当前链表的尾结点。
注意点:
◆ 无论是哪种插入方法,如果要插入建立的单线性链表的结点是n个,算法的时间复杂度均为O(n)。
◆ 单链表的 插入、删除、查找操作的时间复杂度都是 O(n)
◆ 对于单链表,无论是哪种操作,只要涉及到钩链(或重新钩链),如果没有明确给出直接后继,钩链(或重新钩链)的次序必须是“先右后左”
◆ 若La ,Lb两个链表的长度分别是m,n,则链表合并的时间复杂度为O(m+n)
3. 链表的结构体定义:
typedef struct LNode{ ElemType data; struct LNode *next; }LNode;
线性表——循环链表
1. 循环链表:是一种头尾相接的链表。其特点是最后一个结点的指针域指向链表的头结点,整个链表的指针域链接成一个环
注意点:
◆ 判断是否是空链表:head->next==head ;
◆ 判断是否是表尾结点:p->next==head ;
◆ 头结点数据域为空 【包括之前的链表,头结点数据域都是NULL】
线性表——双向链表
1. 双向链表:指的是构成链表的每个结点中设立两个指针域:一个指向其直接前趋的指针域prior,一个指向其直接后继的指针域next。这样形成的链表中有两个方向不同的链,故称为双向链表
注意点:
◆ 结点插入时,切记“先右后左”
◆ 结点删除时,切记 free(p)
typedef struct Dulnode{ ElemType data; struct Dulnode *prior , *next; }DulNode;
2. 双向链表的基本操作:
(1) 插入——仅仅有直接前驱结点,钩链时必须注意先后次序是: “先右后左,从下到上” 。部分语句组如下:
S=(DulNode *)malloc(sizeof(DulNode)); S->data=e; S->next=p->next; p->next->prior=S; p->next=S; S->prior=p;
(2) 插入——有直接前驱结点p和直接后继结点q,钩链时无须注意先后次序。部分语句组如下:
S=(DulNode *)malloc(sizeof(DulNode)); S->data=e; p->next=S; S->next=q; S->prior=p; q->prior=S;
(3) 删除——设要删除的结点为p ,可以直接先断链,再释放结点:
p->prior->next=p->next; p->next->prior=p->prior; free(p);
顺序表和链表存储的优缺点
1.顺序表存储
优点:存取效率高,速度快,通过下标来直接存储
缺点:
◆ 插入和删除比较慢
◆ 不可以增长长度
2.链表存储
优点:
◆ 在程序运行过程中动态的分配空间,只要存储器还有空间,就不会发生存储溢出问题
◆ 插入和删除速度快,保留原有的物理顺序,比如:插入或者删除一个元素时,只需要改变指针指向即可
缺点:
查找速度慢,因为查找时,需要循环链表访问