概述
-
线性表:是一种最常用、最简单,也是最基本的数据结构。
-
线性表由n个数据元素所构成的有限序列,且数据类型相同。
-
线性表可以用
顺序存储
和链式存储
两种存储结构来表示。-
使用
顺序存储
的线性表称为顺序表,也称为静态线性表。 -
使用
链式存储
的线性表称为链表,也称为动态线性表。
-
-
链表的分类:单链表、双向链表、循环链表。
顺序表
定义
-
顺序表,就是顺序存储的线性表。
-
顺序存储是用一组地址连续的存储单元依次存放线性表中各个数据元素的存储结构。
-
在逻辑上,数据ABCD是连续
-
在物理上,地址也是连续的
-
-
可以使用
数组
来描述数据结构中的顺序存储结构。
地址公式
//第i的地址 = 第一个地址 + 第几个 * 存储单位
Loc(ai) = Loc(a0) + i * c
顺序表特点
-
在线性表中逻辑上相邻的数据元素,在物理存储位置上也是相邻的。
-
存储密度高。但需要预先分配“足够”的存储空间。
存储密度 = 数据元素存储空间 / 数据元素实际占用空间
在顺序表中,存储密度为1。
-
便于随机存储。(数组中可以通过下标进行存储)
-
不便于插入和删除操作。两种操作都会引起大量的数据移动。
算法-插入
需求:在顺序表第i个位置处插入一个新元素。
顺序表插入操作:将第i个数据元素及其之后的所有的数据元素,后移一个存储位置,再将新元素插入到i处。
前置:类中成员
public class SqList {
private Object[] listElem; //线性表的存储空间
private int curLen; //线性表的当前长度
}
插入操作算法
/**
* @Param i 第i个位置
* @Param x 需要插入的数据
*/
public void insert(int i, Object x) {
//0.1 满校验:存放实际长度 和 数组长度 一样
if(curLen == listEle.length) {
throw new Exception("已满");
}
//0.2 非法校验,在已有的数据中间插入 [0, curLen],必须连续,中间不能空元素
if(i < 0 || i > curLen) {
throw new Exception("位置非法");
}
//1 将i及其之后后移
for(int j = curLen ; j > i; j --) {
listEle[j] = listEle[j-1];
}
//2 插入i处
listEle[i] = x;
//3 记录长度
curLen ++;
}
插入时间复杂度:O(n)
算法-删除
需求:将第i位置处元素删除
删除操作:将第i个数据元素ai之后的所有数据元素向前一定一个存储位置。
删除操作算法:
public void remove(int i ) throws Exception {
// 0.1 校验非法数据
if(i < 0 || i > curLen - 1 ) {
throw new Exception("位置非法");
}
// 1 将i之后向前移动
for(int j = i ; j < curLen - 1 ; j ++ ) {
listEle[j] = listEle[j+1];
}
// 2 长度减一
curLen--;
}
删除时间复杂度:O(n)
算法:查找
需求:查找指定数据的索引号查找算法实现:
方案1:循环遍历已有数据,进行判断,如果有返回第一个索引号,如果没有返回-1
public int indexOf(Object x) {
for(int i = 0; i < curLen ; i ++) {
if(listEle[i].equals(x)) {
return i;
}
}
return -1;
}
方案2:使用变量记录没有匹配到索引
public int indexOf(Object x) {
int j = 0; //用于记录索引信息
while(j < curLen && !listElem[j].equals(x)) {
j++;
}
// j记录索引小于数量
if(j < curLen ) {
return j;
} else {
return -1
}
}
顺序表局限性
-
若要为线性表扩充存储空间,则需要重新创建一个地址连续的更大的存储空间,并把原有的数据元素都复制到新的存储空间中。(扩容)
-
因为顺序存储要求逻辑上相邻的数据元素,在物理存储位置上也是相邻的,这就使得要增删数据元素时,会引起平均一半的数据元素的移动。