今天来讲讲的数据结构初学中常见的一种——顺序表
当然我们来讲讲什么是顺序表先。
顺序表是属于线性表的一种。
那线性表又是什么呢?
线性表是一种逻辑上连续,但物理上(内存地址不一定连续)不一定连续。
而我们的顺序表呢是一种逻辑上连续,物理上也连续的结构。
既然这样的话,我们顺序表自然可以想到用数组作为底层来实现啦。
既然是一种数据结构,那我们来用java语言实现下基本的操作吧——增删查改
实现这些之前我们我们要创建一些文件先。
图中所示,创建了一个List接口和一个MyArrayList类。
那为啥创建这个List接口呢,是为了将我们的实现的方法放在里面,然后让这个MyArrayList接口来实现它。当然不创键这个接口也行,直接在MyArrayList类里面进行创建方法也是ok的。
那让我们先看看List接口中都有些什么方法吧:
public interface List {
//将要写的方法放在这里实现
void add(int data);//数据尾插
void add(int pos,int data);//指定位置之前插入数据
boolean FindIndex(int toFind);//查找是否包含此元素
int IndexOf(int toFind);//查找某个元素对应的位置
int get(int pos);//获取pos位置的元素
void set(int pos,int value);//将pos位置的元素更新——>value
void remove (int toRemove);//删除第一次出现的关键字key
int size();//获取数组的长度
void clear();//清空数组
void display();//展示顺序表的元素
boolean isFull();//数组是否满了
}
既然底层是数组实现的,那么我们怎么较快速的知道数组是否满了呢?这时候我们用一个变量usedsized来记录当前一个位置。
那就看看代码是咋样的吧。
public class MyArrayList implements List{
int []arr;
int usedSized;
public MyArrayList(){
this.arr=new int[10];
}
}
这里呢我们写定数组的大小为10个元素。
那么数组基本的就结构创建完了。来实现下基本的方法吧。
比如增加功能,增加之前我得想一个细节问题——如果数组满了?我们咋办?那么肯定得扩容咯。
再来想下数组怎么判断是否为满的?
这样子的话我们先实现数组是否为满的这个方法:
为满判断:
public boolean isFull() {
//如何判断为满,当数组长度等于uesdSize
return usedSized==arr.length;
}
接下来才可以增加元素进去。
增加数组元素:
public void add(int data) {
if(isFull()){
//首先判断数组是否满了,满了就要扩容
arr= Arrays.copyOf(arr,2*arr.length);
}
//增添数据
this.arr[usedSized]=data;
usedSized++;
}
不过我们得注意下,useSized得记得+1。
增加元素还有个方法呢,让我们玩点另外一个不同,在pos位置前增加一个元素。
pos位置前增元素
那么问题来了,pos位置这个位置合不合法呢?那肯定是不能保证的是吧,因为我们可以随便输入咯,所以我们得判断以下是否合法的,
那么不用简单的ifelse来判断。用一个异常来告诉我们pos是不合法的。
所以我们创建一个异常类:
public class PosNotLegalException extends RuntimeException {
public PosNotLegalException(){
}
public PosNotLegalException(String error){
super(error);
}
}
我们这个异常类得继承这个运行时异常,因为我们运行时才能确定这个pos是否合法的。
然后我们在add方法里再用try catch语句进行打印这个异常:
代码实现:
public void add(int pos, int data) {//在指定位置插入数据
//判断pos是否合法
try{
checkPos(pos);
}catch (PosNotLegalException e){
e.printStackTrace();
}
//指定位置前插入元素
for(int i=usedSized-1;i>=pos;i--){
arr[i+1]=arr[i];
}
arr[pos]=data;
usedSized++;
}
public void checkPos(int pos)throws PosNotLegalException{
if(pos<0||pos>usedSized){
System.out.println("pos位置不合法!");
}
}
说明:怎么插入呢,先把pos和usedsized之间的元素往右移动,空出一个空格就可以插入元素。
值得注意的是,我们add方法在这里是进行方法的重载了的。
接下来我们实现另一个方法:
查找某个元素对应的位置:
先上代码再来说过程:
public int IndexOf(int toFind) {
//查找对应元素的位置
for(int i=0;i<usedSized;i++){
if(arr[i]==toFind){
return i;
}
}
return -1;
}
这个过程是挺简单的,用一个循环来遍历0--usedsized范围内。
如果我们数组的值等于这给定的tofind就返回下标。
与此类似的是另一个方法是:
查找是否包含此元素:
public boolean FindIndex(int toFind) {
//寻找该元素是否存在
for(int i=0;i<arr.length;i++){
if(arr[i]==toFind){
return true;
}
}
return false;
}
逻辑简单这里就不多赘叙了。
接下来我们实现一个更简单的的方法:
获取pos位置的元素:
直接上代码:
public int get(int pos) {
//依旧是判断pos位置是否合法
try{
checkPos(pos);
}catch (PosNotLegalException e){
e.printStackTrace();
}
return arr[pos];
}
当然我们这里也是需要用一个异常处理来判断下pos位置知否合法的呢。
这些简单点的方法还有几个呢,那我们一起来处理它们吧。
获取数组长度:
public int size() {
//获取数组的长度
int count=0;
for (int i=0;i<usedSized;i++){
count++;
}
return count;
}
方法呢用一个循环和一个计数器就好了。
打印数组:
public void display() {
//如何展示数组数据?遍历数组打印
for(int i=0;i<usedSized;i++){
int tmp=arr[i];
System.out.print(tmp+" ");
}
}
前面写了增加和查找的方法,那么接下来写个改的方法吧。
更新元素:
先上代码:
public void set(int pos, int value) {
//将pos元素设置相对应的值,依旧要判断是否合法
try{
checkPos(pos);
}catch (PosNotLegalException e){
e.printStackTrace();
}
for(int i=0;i<arr.length;i++){
if(i==pos){
arr[i]=value;
return;
}
}
}
同样我们这里也需要判断下pos位置是否合法。
思路也是挺简单的,直接遍历数组。然后找到后,重新赋值。
接下来还有个有点小难的方法呢:
删除所提供的数字:
先上代码:
public void remove(int toRemove) {
//删除第一次出现的关键字
int pos = IndexOf(toRemove);
if(pos == -1) {
System.out.println("没有要删除的数字!");
return;
}
for (int i = pos; i < usedSized-1; i++) {
arr[i] = arr[i+1];
}
usedSized--;
}
思路呢,也是蛮简单的,先将把toRmove传给 Indexof,然后这个方法找到在哪,然后在循环中,将pos--usedsized之间的元素中的后一个元素进行覆盖,这样呢就完成了删除。
最后一个方法就是清空数组:
清空数组:
public void clear() {
//两种办法,循环置为null、或者usedSized=0;
usedSized=0;
}
但这里是基本类型,赋值null是不行的。
至此,我们简易的顺序表已写完。
完!