👉 原文首发: 小牛肉的个人博客,欢迎来访~
文章目录
一、线性表的定义:
具有相同数据类型的n个数据元素的有限序列
线性表是一种逻辑结构,表示元素之间一对一的逻辑关系。顺序表和链表是表示存储结构。
二、顺序表
1. 顺序表定义:
线性表的顺序存储
typedef struct{
int data[50];
int length;
} SqList;
逻辑上相邻的两个元素在物理位置上也相邻
特点:
- 随机访问(通过首地址和元素序号可在时间O(1)内找到元素)
- 插入和删除需要移动大量元素
- 存储密度高,每个结点只存储数据元素
2. 顺序表基本操作
插入
在第i个位置(下标i-1)插入元素e
//第i个元素及其之后的元素后移
for (int j = length; j >= i; j--)
L[j] = L[j - 1];
L[i - 1] = e;
length++;
- 最好情况:在表尾插入,时间复杂度 O(1)
- 最坏情况:在表头插入,时间复杂度 O(n)
- 平均情况:时间复杂度 O(n)
删除
删除第i个位置的元素,用e返回
e = L[i-1];
//从第i个位置元素前移
for(int j = i; j<length;j++)
L[j-1] = L[j];
length --;
- 最好情况:删除表尾元素,O(1)
- 最坏情况:删除表头元素,O(n)
- 平均情况:O(n)
按值查找
for (int i = 0; i < length; i++)
if (L[i] == e)
return i;
- 最好情况:查找元素在表头,O(1)
- 最坏情况:查找元素在表尾,O(n)
- 平均情况:O(n)
三、链表
链表分为:
- 单链表
- 双链表
- 循环单链表(判空条件:表尾结点的next是否是等于头指针)
- 循环双链表
1. 单链表
定义
typedef struct LNode{
ElemType data;
struct LNode* next;
}LNode,*LinkList;
单链表可以解决顺序表需要大量连续存储空间的缺点,但单链表附加指针域,也存在浪费存储空间的缺点
单链表是非随机存储的存储结构:即不能直接找到表中某个特点的结点。需要从头开始遍历。
------> 单链表访问前驱的时间复杂度为O(n),访问后继O(1)
引入头节点的优点:
- 链表的第一个元素位置上的操作与其他位置的元素操作一样,无须进行特殊处理
- 无论链表是否为空,其头指针都是指向头节点的非空指针,空表和非空表的处理得到了统一
(头指针始终指向第一个结点,有头节点则指向头节点,无头节点则指向第一个元素结点)
基本操作
头插法:(读入顺序和生成顺序相反)
s->next = L->next;
L->next = s;
尾插法:(读入顺序和生成顺序相同)
//尾指针r
r->next = s;
r = s;
按序号查找
按值查找
插入结点:
p之后插入s(p的位置需要自行查找)
s->next = p->next;
p->next = s;
删除结点:
//删除p之后的q
q = p->next;
p->next = q->next;
free(q); //释放结点的存储空间
求表长
2. 双链表
定义
就是同时具有前驱指针和后继指针的链表
访问前驱和后继结点时间复杂度都是O(1)
typedef struct DNode{
int data;
struct DNode* next,*prior;
}DNode,*DinkList;
基本操作
插入:
p之后插入s
s->next = p->next;
p->next->prior = s;
p->next = s;
s->prior = p;
删除:
//删除p之后的s
p->next = s->next;
s->next->prior = p;
free(s);