数据结构初学,应该先了解何为数据结构。按照最简单的理解,数据结构就是存储数据的方式。这种结构包括逻辑结构和存储结构:逻辑结构其实是人脑构想的逻辑,例如树的概念,计算机存储数据时树并不存在,但为了方便实现一定的功能,人为构造了树的概念;存储结构即为计算机真实存储数据的结构。这里不得不提出算法,算法和数据结构是相辅相成的:选定了合适的数据结构,算法就方便实现;有了合适的算法,数据结构容易被存取。
Day1解释数据结构中的第一个概念:基于数组的线性表。线性表(Linear List),顾名思义,就是一维数组顺序排列下的一维表。写线性表需要通过接口来实现,所以先定义接口。
//线性表的接口定义
public interface MyList {
//功能实现
//增加元素
void add(Object element);
//删除指定元素
void delete(Object element);
//根据索引删除元素
void delete(int index);
//更新索引元素
void update(int index,Object element);
//查看制定元素是否在列表中
boolean contains(Object element);
//返回指定元素的下标
int indexOf(Object element);
//返回下标指定元素
Object at(int index);
}
由于线性表可以实现的功能包括元素的增加、删除(包括指定下标或元素删除)、修改(又叫更新)、判断给定元素是否在表内、获取给定下标所在处的元素,所以写出接口的上述功能。
下面,定义一个线性表,实现接口。
public class MyArrayList implements MyList {
int size=0;//存储的元素个数-1(方便使用下标)
int capacity=5;//最大容量
Object[] arr=new Object[capacity];
//设置最大容量
public MyArrayList(int capacity) {
this.capacity = capacity;
}
public MyArrayList() {
}
@Override
public void add(Object element) {
if(size==capacity){//当size到头时,capability要扩容
capacity*=2;//一般扩大成原来的两倍
Object[] newArr=new Object[capacity];
for(int i=0;i<size;i++){
newArr[i]=arr[i];
}
arr=newArr;
}
arr[size++]=element;
}
@Override
public void delete(Object element) {
//删除指定元素后,该位元素清零,空位后面的元素向前挪一位补齐
for(int i=0;i<size;i++){//扫描size个元素的方式找出element
if(arr[i]==element){
arr[i]=0;
for(int j=i;j<=size-1;j++){
arr[j]=arr[j+1];
}
arr[size--]=0;
break;
}
}
}
@Override
public void delete(int index) {
//同上述delete方法,不同在于根据索引找删除的元素
arr[index]=0;//清零
for(int i=index;i<=size-1;i++){
arr[i]=arr[i+1];//向前挪
}
arr[size--]=0;
}
@Override
public void update(int index, Object element) {
arr[index]=element;
}
@Override
public boolean contains(Object element) {
for(Object i:arr){
if(i==element) return true;
}
return false;
}
@Override
public int indexOf(Object element) {
for(int i=0;i<size;i++){
if(arr[i]==element) return i;
}
return -1;
}
@Override
public Object at(int index) {
if(index<=size) return arr[index];
return "so sad, not here";
}
//输出,便于查看测试结果
public void outPut(){
System.out.print("[");
for(int i=0;i<size;i++){
System.out.print(i==size-1?arr[i]:arr[i]+" ");
}
System.out.println("]");
}
}
在这里有个小坑:线性表并非动态数组,因此当元素个数大于表的最大容量时,需要扩容。扩容一般是将原数组的最大容量扩大为两倍,然后定义一个新数组,把原有元素挪到新数组中,把新数组索引给原数组。这样就间接扔掉了原数组,创建了新数组。群众雪亮的眼镜应该已经发现,这样做会浪费内存,也算是线性表的缺点吧。
写到这里,表的定义以及完成,还差测试结果。测试如下:
public class MyArrayListTest {
public static void main(String[] args) {
MyArrayList arrayList=new MyArrayList();
arrayList.add("nb");//测试size下标小于capability
arrayList.add("只因");
arrayList.add("drag");
arrayList.add("queen");
arrayList.add("queer");
arrayList.add("bug");//加到这里出现bug,由于arr数组越界
arrayList.add("bugRemoved");
arrayList.outPut();//实现扩容后测试
arrayList.delete(2);
arrayList.outPut();//测试指定下标删除
arrayList.delete("queen");
arrayList.outPut();//测试指定元素删除
arrayList.update(1,"只因你太美");
arrayList.outPut();//测试更新功能
System.out.println(arrayList.contains("鸡"));//测试查找功能
if(arrayList.indexOf("只因你实在是太美")==-1) System.out.println("so sad, not here");
else System.out.println(arrayList.indexOf("只因你实在是太美"));//测试不存在元素查找下标
if(arrayList.indexOf("只因你太美")==-1) System.out.println("so sad, not here");
else System.out.println(arrayList.indexOf("只因你太美"));//测试存在元素查找下标
System.out.println(arrayList.at(1));//测试存在下标的元素
System.out.println(arrayList.at(90));//测试不存在下标的元素
}
}
运行结果:
[nb 只因 drag queen queer bug bugRemoved]
[nb 只因 queen queer bug bugRemoved]
[nb 只因 queer bug bugRemoved]
[nb 只因你太美 queer bug bugRemoved]
false
so sad, not here
1
只因你太美
so sad, not here
Process finished with exit code 0