1. 元素移动次数计算问题
本问题针对顺序表, 因为链表不需要移动元素, 只需要重新连接指针即可.
题型一:
计算在某个位置上插入一个新元素会导致多少元素的移动.
题型二:
计算在每个位置上插入一个元素所导致的平均移动次数. 先计算每个位置上插入的概率, 一般是1/n, 平均移动次数 = 每个位置上进行插入操作所导致的元素移动次数 * 每个位置上发生插入操作的概率(一般是1/n))
1. 顺序表插入元素, 元素移动次数计算问题
n个元素的顺序表有n+1个可插入位置. 在任一位置插入元素的概率为 p = 1/(n+1), 用i代表顺序表中所有的位置, i 的取值范围是[0, n], 共n+1个, n即为表中最后一个元素后面的位置.
在 i 号位置前进行插入操作, 所导致的元素移动个数是多少呢?
方法: 举例归纳. i = 0, 移动n个元素; i = 1, 移动n - 1个元素......
在 i 位置( i 的取值: 0~n)之前插入元素, 需要移动n - i 个元素.
在一个长度为n的线性表中插入一个元素所需要的平均移动次数, 如何计算?
0位置, 移动n个元素; 1位置, 移动1个元素; ...... n位置, 移动0个元素.
总移动次数为: (n+0) * (n+1) / 2;
平均移动次数: 1/(n+1) * (n+0) * (n+1) / 2 = n / 2;
插入元素平均要移动的元素个数为: n / 2. (理解推导过程, 不要死记, 题目会有小陷阱)
2. 顺序表删除元素, 元素移动次数计算问题
n个元素的顺序表有n个可删除位置.
在任一位置删除元素的概率为: p = 1 / n;
在 i 位置( i 的取值: 0~n - 1)删除元素, 需要移动n - 1 - i 个元素;
0位置, 移动n - 1个元素; 1位置, 移动n - 2个元素; ...... n - 1位置, 移动0个元素.
总移动次数为: (n - 1 + 0) * n / 2;
平均移动次数: 1/n * (n - 1 + 0) * n / 2 = (n - 1) / 2; (注意一共n项, 而不是n - 1项)
2. 静态链表
静态分配: 对于某种存储结构, 其存储空间如果是一次性分配, 就叫静态分配;
动态分配: 对于某种存储结构, 其存储空间如果是多次分配的, 就叫动态分配;
因此顺序表的存储空间是静态分配的, 链表的存储空间是动态分配的.
静态链表的存储空间是静态分配的, 我们给它分配了一个顺序表, 只不过在这一片顺序存储空间上通过一些方法实现了一种类似于链表的存储结构.
#include <iostream>
const int MAX_SIZE = 10;
/// <summary>
/// 静态链表结构体定义
/// </summary>
typedef struct{
int data;
int next; //静态链表的关键, 通过整型下标定位
}SLNode;
int main()
{
SLNode SLink[MAX_SIZE];
//定义结点
SLNode node0;
node0.data = 0;
SLNode node1;
node1.data = 1;
SLNode node2;
node2.data = 2;
//结点放入数组
SLink[0] = node0;
SLink[2] = node1;
SLink[4] = node2;
//连接结点, 连接node0与node2
SLink[0].next = 4;
SLink[4].next = -1;
//插入操作, 在node0与node2之间插入node1
SLink[2].next = SLink[0].next;
SLink[0].next = 2;
int p = 0;
while (p != -1)
{
printf("%d\n", SLink[p]);
p = SLink[p].next;
}
}
代码1: 静态链表的基本操作
next分量存储的是"指针", 它不是严格意义上的指针型变量, 它存储的是指向下一个链表结点的"地址", "地址"也不是严格意义上的地址, 它只是数组下标.
在该数组中所存储的静态链表的结点并不是挨着的, 而是散落地分布的, 表结点之间的关系是怎么体现的呢? node0的后继是谁? 是node1, node0的next分量存储的是node1的数组下标, 其他的结点也是同样的情况, 这一点类似于链表, 虽然表的存储单元不挨着, 但我们可以用一个"指针"把它们串起来, 来反映它们之间的逻辑结构.