基本概念
线性表,就是将数据排成像一条长线一样的结构,数组,链表,栈,队列都 是线性表结构,线性表上的数据最多只有前后两个方向,下面以一幅图的形式来展现一下线性表结构
补充:
与这种线性结构对应的就是非线性结构,比如后续要学习的数,堆,图等,在这些非线性数据结构 中,数据之间并不是简单的前后关系,如下图:
线性表的存储结构
线性表在计算机中可以用顺序存储和链式存储两种存储结构来表示:
- 顺序存储结构的线性表:顺序表
- 链式存储结构的线性表:链表又分为单链表、双向链表、循环链表
线性表的特点
- 由多个同类型发元素组成
- 因是线状的,除第一个和最后一个之外,最多只有两个方向
- 长度可以动态的增长或减少
- 可以访问所有元素
- 在任意位置进行插入和删除
- 求线性表的前驱和后继
线性表的基本操作
基本操作
1.线性表的置空操作:clear()
2.线性表判空操作:isEmpty()
3.求线性表元素的个数:length()、size()
4.求线性表的容量:getCapacity()
5.取元素操作:get(i)
6.插入操作:insert(i,x)
7.删除操作:remove(i)
8.查找操作:indexOf(i)
9.输出操作:display()
手写ArrayList
/**
* 线性表的实现方式一:顺序表,采用数组实现
* 换种说法:手写一个ArrayList(线性表的顺序结构的实现方式)
*
* 需要哪些内容?
* 1 数组:存放数据
* 2 size:存放数组中元素的个数
*
* 3 构造方法:空参构造,数组初始化大小10
* 带参构造,数组大小就是传递过来的值
* 4 getCapacity:获取数组容量,大小
* 5 getSize:获取元素个数
* 6 isEmpty:是否为空 ,size==0
*
* Array<Student>
* Array<User>
* Array<Book>
*
*/
public class Array<E> {
//数组
private E[] data;
//元素的个数
private int size;
//空参构造
public Array(){
//调用本类的其他构造方法
this(10);
}
//带参构造
public Array(int capacity){
data = (E[]) new Object[capacity];
size = 0;
}
//获取数组容量
public int getCapacity(){
return data.length;
}
//获取元素个数
public int getSize(){
return size;
}
//判断是否为空 size==0
public boolean isEmpty(){
return size==0;
}
//向指定index索引新增元素e
/**
* 思路分析:
* 1 防止数据被覆盖,所以需要从size-->index位置诺元素
* 2 data[index] = e
* 3 size++
*/
public void add(int index,E e){
//1 数组满?size == data.length
if(size == data.length) {
// throw new RuntimeException("数组已满,请扩容");
resize(2 * data.length);
}
//2 index<0 index>size? index>data.length?
//数组的长度为10,index = 10 ,size = 10
// index=9 size=9
// index = 0 size = 0
if (index<0||index>size)
throw new RuntimeException("索引非法");
//1 挪:从sise-1的位置挪到index位置
for (int i=size-1;i>=index;i--){
data[i+1]=data[i];
}
//2 赋值
data[index] = e;
//3 size++
size++;
}
//指定在队首新增
public void addFirst(E e){
add(0,e);
}
//指定在队尾新增
public void addLast(E e){
add(size,e);
}
//查找:list.get(i)
public E get(int index){
//索引非法判断
if(index<0||index>=size)
throw new RuntimeException("索引非法");
//索引没问题
return data[index];
}
//查找:list.find(e)
//如果找到元素,返回索引index
//如果找不到,返回-1
//e全称element,元素
public int find(E e){
//1 遍历数组--if比较,找到返回index
for (int i=0;i<size;i++){
if (data[i].equals(e)){
return i;
}
}
//2 找不到,返回-1
return -1;
}
//修改:修改指定index索引位置的元素
public void set(int index,E e){
if(index<0||index>=size)
throw new RuntimeException("索引非法");
data[index] = e;
}
//contains:包含:判断数组中是否包含某个元素
//参数:判断的元素
//返回值:true 存在,false不存在
public boolean contains(E e){
//遍历-比较
for (int i=0;i<size;i++){
if (data[i].equals(e)){
return true;
}
}
return false;
}
//设计remove的时候,需要返回刚刚被删除的值
public E remove(int index){
//1 判断index是否合法
if (index<0||index>=size)
throw new RuntimeException("索引非法");
//2 保存要删除的值
E del = data[index];
//3 删除-移动元素-size位置清空,维护size
for (int i = index+1;i<size;i++){
data[i-1]=data[i];
}
data[size-1] = null;
size--;
//缩减容量
if (size == data.length / 2)
resize(data.length/2);
//4 返回删除的值
return del;
}
//删除首元素
public E removeFirst(){
return remove(0);
}
//删除最后一个元素
public E removeLast(){
return remove(size-1);
}
//删除指定元素
public E removeElement(E e){
int index = find(e);
E remove = remove(index);
return remove;
}
//动态扩容
public void resize(int newCapacity){
//1 创建一个新的数组
E[] newData = (E[]) new Object[newCapacity];
//2 将老数组的值一一复制过来
for (int i=0;i<size;i++)
newData[i] = data[i];
//3 将新数组赋值给data
data = newData;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
for (int i=0;i<data.length;i++){
sb.append(data[i]);
if(i!=data.length-1){
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
}