NO.2数据结构线性表|线性表|顺序表|链表|单链表|双向链表|循环链表|静态链表|插入|删除
★c/c++内存的划分
线性表
定义:
线性表是 n 个具有相同特性的数据元素组成的有限的有序序列。
【有序】 逻辑上有先后顺序, 而非物理位置上的前后次序
” 四个一” 特点
- 存在唯一的一个被称为“第一个” 的元素
- 存在唯一的一个被称为“最后一个” 的元素
- 除第一个之外, 其他各个元素只有唯一的前驱
- 除最后一个之外, 其他各个元素只有唯一的后继
应用场合
线性表是最简单、 最常用的一种数据结构。
对于一个实际问题, 如果该问题中包括的各个数据性质相同, 各个数据之间没有层次关系并且每个元素最多和其他两个元素有关系, 这时就可以将实际问题抽象成线性关系。
例如集合问题、 学生信息、 若干年的国民收入等
顺序表
定义:
顺序表即线性表的顺序表示, 就是用一组地址连续的内存单元依次存储线性表的各个元素。 就是说, 逻辑上相邻的元素一定是存储在相邻的物理空间中。
物理结构
顺序存储, 但是分为静态分配和动态分配两种方式。 两种方式的数据结构定义也各有不同。
typedef struct{ Elemetype data[MaxSize]; int length;
}SqList; //静态分配typedef struct{ Elemetype *data; int MaxSize, length;
}SeqList; //动态分配//C:
(Elemtype*)malloc(sizeof(Elemtype) *Size)
//C++:
new Elemtype[Size]
其中静态分配的数组会出现溢出的情况, 动态分配的数组当出现溢出时, 系统会寻找一块更大的内存整体移动过去。
特点
【优点】 无需为表示元素间的逻辑关系而增加额外的存储空间, 可以方便地随机存取表中的任一元素。
【缺点】 要求占用一整片连续的空间, 而且插入和删除元素时需要移动大量的元素,如在含 n 个元素的顺序表中插入一个元素时, 需平均移动 n/2 个元素, 删除一个元素时, 需平 均移动(n-1)/2 个元素。
应用场景
顺序表主要应用在数据量不大, 且很少有插入、 删除操作的场合。
链表
定义:
链表即线性表的链式表示。
就是用一组任意的存储单元存储线性表的数据元素 (这组存储单元可以是连续的, 也可以是不连续的) 根据是否整体申请内存空间, 链表分为动态链表和静态链表。
【动态链表】 根据实际需要, 有一个元素申请一个“结点” 空间, 此时各个元素的逻辑关系只能通过各个结点的内存地址来标识。
【静态链表】 事先申请一定量的内存空间, 逻辑上相邻的元素不一定放在相邻的位置。
单链表
数据结构
typedef struct LinkedList { LNode *head;
}LinkedList; //单链表typedef struct LNode { Elemtype data; struct LNode *next;
}LNode; //节点
★ 注: 不要把单链表的数据结构和节点的数据结构混为一谈。
定义:
在每个节点中除包含数据域外, 只设置一个指针域, 用以指向其后继节点。
★ 头结点, 头指针, 首元节点
头指针是指向链表第一个节点的指针, 以头指针来命名链表, 如 L。
首元节点是链表的第一个保存元素值的节点。
为了方便操作会在首元节点前面加一个 data 域为 null 的头结点。
★ 注: 一个链表的第一个节点要么是头节点, 要么是首元节点。
头节点的好处
- 方便对链表进行操作,增加代码的可复用性;
- 统一了空表与非空表的操作以及头指针类型;
- 单链表一般都是带头结点的,但是在做选择题的时候如果题目没有声明,那就是不带头结点。
带头节点的单链表
不带头节点的单链表
应用场景
单向链表不必占用一块连续的内存空间, 在查找、 取值等静态操作比较少, 增加、删除操作比较多的情况下, 单向链表应用较多。
双向链表
数据结构
typedef struct DLinkedList { DNode *prior; DNode *next;
}DLinkedList; //双链表typedef struct DNode { Elemtype data; struct DNode *prior; struct DNode *next;
}DNode; //节点
定义:
在每个节点中除包含数据域外, 设置有两个指针域, 分别用以指向其前驱节点和后继节点。
带头节点的双链表
不带头节点的双链表
应用场景
从任何一个结点开始均可以很方便地访问它前后的节点。
循环链表
定义:
循环链表是另一种形式的链式存储结构。 它的特点是表中尾节点的指针域不再是空, 而是指向表头节点, 整个链表形成一个环。 由此, 从表中任一节点出发均可找到链表中的其他节点。
循环单链表
循环双链表
静态链表
数据结构
typedef struct LNode { Elemtype data; int cur;
}SLinkedList[100]; //假设申请 100 个连续的内存空间
借用一维数组来描述线性链表。
数组中的一个分量表示一个节点, 同时使用游标(指示器 cur) 代替指针以指示节点在数组中的相对位置。
数组中的第 0 个分量可以看成头节点, 其指针域指示静态链表的第一个节点。
静态链表是利用数组表示的链式存储结构
应用场景
存储时间要求高的场合。
例如, 实时系统的具体应用
【优点】
在链表中插入或删除操作时, 只需修改相关节点的指针域即可, 不需移动节点
【缺点】
- 由于每个节点带有指针域, 因而在存储空间上比顺序表要付出较大的代价, 所以顺序表比链表的存储密度更高
- 链表不具有顺序表的随机存取特点
顺序表与链表的比较
线性表的基本操作
建立单链表
尾插法: 尾插法每次都将新节点插入在当前工作节点(表尾)之后。
头插法: 头插法每次都将新节点插入在头节点(表头)之后。
单链表的插入操作
(时间复杂度 O(n))
核心思想: 插入新的节点之后不会使其“断链” .
单链表的删除
(时间复杂度 O(n))
核心思想: 1. 不要“断链” 。 2. 需记住删除的节点以防后面用到。
双向循环链表的插入
(时间复杂度 O(n))
核心思想: 不要“断链” , 不要先处理插入位置的前驱节点的后继指针。
双向循环链表的删除
(时间复杂度 O(n))
核心思想: 先处理被删除节点的前驱节点或者后继节点都可以。