根据数据结构的逻辑结构来分:数据元素之间存在的关联关系被称为数据间的逻辑结构。分为一下4类:
1.集合:数据元素之间只有“同属于一个集合”关系
2.线性结构 : 数据元素间存在一对一的关系 ---- 线性表
1.集合:数据元素之间只有“同属于一个集合”关系
2.线性结构 : 数据元素间存在一对一的关系 ---- 线性表
非线性结构: 图和树
3.树形结构 : 数据元素之间存在一对多的关系
4.图状或者网状结构 : 数据元素间存在多对多的关系
3.树形结构 : 数据元素之间存在一对多的关系
4.图状或者网状结构 : 数据元素间存在多对多的关系
而在计算机在物理磁盘上通常是2种物理存储结构: 顺序存储结构、链式存储结构。
在之前已经写过的文章中,我也都是分别介绍这两种的存储结构的实现。这一篇先介绍线性表的基本概念和顺序存储结构的实现。
线性表(linear list):是由n个数据元素(节点)组成的有限序列。其中每个元素都要有相同的结构(即相同的数据项)。此外在较为复杂的线性表中每个数据元素其实可以包含若干个数据项。
定义:
当n>0时可表示为(a1, a2, a3, a4, a5.....an)。线性表中包含的数据元素个数n被称为表的长度,当线性表的长度为0时被称为空表。
基本特征:
1.总存在唯一的“第一个”数据元素。
2. 总存在唯一的“最后一个”数据元素。
3. 除了first外, 集合中每个元素都只有一个前驱的数据元素。
4. 除了last外, 集合中每一个元素都有一个后继的数据元素。
基本操作:
1.init()初始化:通常是一个构造器,用于创建一个空的线性表
2.length()长度 : 返回线性表中的数据元素的个数
3.按值查找元素的位置: 如果一个线性表中存在多个相同的值, 而返回第一个与搜索值相同的位置, 否则 -1
4.直接插入数据元素: 向线性表的头部处插入一个数据元素, 线性表长 + 1
5.指定位置插入数据元素: 向线性表的指定索引处插入一个数据元素, 线性表长 + 1
6.直接删除一个元素:删除头部的数据元素, 长度 - 1
7.删除指定位置的数据元素: 删除线性表指定索引出的数据元素, 长度 - 1
8.判断是否为空 : 空 - true 非空 - false
9.清空操作: clear
顺序存储:是利用一段地址连续的存储单元依次存储线性表的数据元素。这里是定义了一个底层的数组来存储数据,分配给数组的长度是一定的,而线性表的长度会随着增,删而改变的。
参考代码:
public class SequenceList<T> {
private int DEFAULT_SIZE = 20;
//保存数组长度
private int capacity;
//定义一个存储顺序线性表的元素
private Object[] elementData;
//保存当前线性表的个数
private int size = 0;
//以默认的数组长度创建空的顺序线性表
public SequenceList(){
this.capacity = DEFAULT_SIZE;
elementData = new Object[capacity];
}
//以一个初始化的元素来创建顺序线性表
public SequenceList(T element){
this();
elementData[0] = element;
size ++;
}
/**
*
* @param element 指定顺序线性表的第一个元素
* @param initSize 指定顺序线性表的底层数组长度
*/
public SequenceList(T element, int initSize){
// this.capacity = initSize;
capacity = 1;
//把capacity 设为大于initSize的最小的2的n次方
while(capacity < initSize){
capacity <<= 1; //左移一位 实际上就是乘以 2
}
elementData = new Object[capacity];
elementData[0] = element;
size ++;
}
//返回顺序线性表的大小
public int length(){
return size;
}
//获取顺序线性表中索引为i处的元素
public T get(int i){
if(i < 0 || i > size - 1){
throw new IndexOutOfBoundsException("线性表越界!");
}
return (T) elementData[i];
}
//查找指定索引位置的元素
public int locate(T element){
for(int i =0; i < size; i ++){
if(elementData[i].equals(element)){
return i;
}
}
return -1;
}
//向线性表的指定位置插一个元素
public void insert(T element, int index){
if(index < 0 || index > size){//需要插入数据
throw new IndexOutOfBoundsException("线性表越界!");
}
ensureCapacity(size + 1);
//将指定索引处之后的元素都后移
/**
* arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
* src : 原数组 srcPos : 从元数据的起始位置开始
* dest : 目标数组 destPos : 目标数组的开始起始位置
* length : 要copy的数组的长度
*/
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element;
size ++;
}
//扩充数组长度
private void ensureCapacity(int nowCapacity) {
//如果原长度小于现在所需的长度
if(nowCapacity > capacity){
//不断将capacity * 2, 直到大于nowCapacity
while(capacity < nowCapacity){
capacity <<= 1;
}
//copyOf()在内部新建一个数组,调用arrayCopy()将original内容复制到copy中去,并且长度为newLength。返回copy;
elementData = Arrays.copyOf(elementData, capacity);
}
}
//线性表开始处添加元素
public void add(T element){
insert(element, size);
}
//删除线性表的指定位置元素
public T delete(int index){
if(index < 0 || index > size - 1){
throw new IndexOutOfBoundsException("线性表越界!");
}
T oldValue = (T)elementData[index];
int numMoved = size - index - 1;
if(numMoved > 0){
System.arraycopy(elementData, index + 1, elementData, index , numMoved);
}
elementData[--size] = null;
return oldValue;
}
//删除最后一个元素
public T remove(){
return delete(size - 1);
}
//判断是否为空
public boolean empty(){
return size == 0;
}
//清空线性表
public void clear(){
//底层清空 Arrays.fill()只适合于把数组用同一个值初始化。
Arrays.fill(elementData, null);
size = 0;
}
public String toString(){
if(size == 0){
return "[]";
}
else{
StringBuffer sb = new StringBuffer("[");
for(int i = 0; i < size; i ++){
sb.append(elementData[i].toString() + ", ");//这里, 后面的空格很重要, 否则输出时可能出错
}
int len = sb.length();
return sb.delete(len - 2, len).append("]").toString();
}
}
}
测试:
public static void main(String[] args) {
SequenceList<String> list = new SequenceList<String>();
list.add("aa");
list.add("bb");
System.out.println(list);
System.out.println("bb在list中的位置:" + list.locate("bb"));
list.insert("cc", 1);
System.out.println(list);
list.delete(2);
System.out.println(list);
}
线性表的优点:1.无需为表示表中数据元素之间的逻辑关系而增加额外的存储空间。
2.可以快速的存取表中任意位置的元素。
缺点:1.插入和删除是需要移动大量数据。
2.线性表长度变化较大时,难以确定存储空间的容量。
3.造成空间的"碎片"。
以上就是这篇的主要内容,若是有什么错误之处或者可以改进的地方, 请您指出,谢谢!