Java实现数据结构基本算法——(一)顺序表的实现
一、线性表的顺序存储结构——定义
线性表的顺序存储时一组用连续的内存单元依次存放线性表的数据元素,元素在内存的物理存储次序与它们在线性表中的逻辑次序相同,即元素 a[i] 与其直接前驱 a[i-1] 及直接后继 a[i+1] 的存储位置相邻。顺序存储的线性表也称为顺序表。
二、线性表的顺序存储结构——结构分析
线性表的数据元素属于同一类型数据类型,设每个元素占C字节,a0的存储位置为Loc(a0),则 ai 的存储地址为Loc( ai )为:Loc(ai) = Loc(ai) + i * c
顺序表元素 ai 的存储地址是他在线性表中位置 i 的线性函数(如表所示),与线性表长度 n 无关;而计算一个元素地址所需时间是一个常量,与元素位置 i 无关。因此,存取任何一个元素的时间复杂度是 O(1)。换言之,顺序表是一种随机存取结构。
index | 数据元素 | 存储地址 |
---|---|---|
0 | a0 | Loc(a0) |
1 | a1 | Loc(a0) + c |
… | ||
i - 1 | ai-1 | Loc(a0) + (i-1) * c |
i | ai | Loc(a0) + i * c |
i + 1 | ai+1 | Loc(a0) + (i+1) * c |
… | ||
n - 1 | an-1 | Loc(a0) + (n-1) * c |
n | an | Loc(a0) + n * c |
三、接口的声明
public interface LList<E> { //线性表接口
boolean isEmpty(); //判断线性表是否为空,若空返回true
int length(); //返回线性表长度
E get(int index); //返回序号为index的对象,index初始值为0
E set(int index,E element); //设置序号为index的对象为element,返回原对象
boolean add(int index,E element); //插入element对象,插入后对象序号为index
boolean add(E element); //插入element对象,插入位置没有约定
E remove(int index); //移去序号为index的对象,返回被移去对象
void clear(); //清空线性表
public String toString(); //打印线性表
}
四、类与方法的声明
public class SeqList<E> implements LList<E>{ //顺序表类,实现线性接口
private Object[] table; //对象数组,私用成员
private int n; //顺序表长度
//构造方法,创建指定容量的空表
public SeqList(int capacity){}
//指定空表的默认容量
public SeqList(){}
//判断顺序表是否为空,若空返回true
public boolean isEmpty() {}
//返回顺序表长度
public int length() {}
//返回index(初值为0)位置的对象,若序号无效,返回null
public E get(int index) {}
//设置index位置的对象为element,若操作成功,返回原对象,否则返回null
public E set(int index, E element) {}
//在index位置插入element对象,若操作成功返回true,不能插入null
public boolean add(int index, E element) {}
//在顺序表最后插入element对象
public boolean add(E element) {}
//移去index位置的对象,若操作成功,则返回被移去对象,否则返回null
public E remove(int index) {}
//清空顺序表
public void clear() {}
//返回显示所有元素值的字符串,形式为(,)
public String toString(){}
//菜单
public void mean(){}
}
五、具体的方法实现
1. 创建指定容量的空表;
public SeqList(int capacity){ //构造方法,创建指定容量的空表
this.table = new Object[Math.abs(capacity)]; //Math.abs(i)返回参数的绝对值
this.n = 0;
}
2. 指定空表的默认容量;
public SeqList(){ //指定空表的默认容量
this(16);
}
3. 判断顺序表是否为空,若空返回true;
public boolean isEmpty() { //判断顺序表是否为空,若空返回true
return this.n == 0;
}
4. 返回顺序表长度;
public int length() { //返回顺序表长度
return this.n;
}
5. 返回index(初值为0),若序号无效,则返回null;
//设置index位置的对象为element,若操作成功,返回原对象,否则返回null
public E set(int index, E element) {
if(index >= 0 && index < this.n && element != null){
E old = (E) this.table[index];
this.table[index] = element;
return old;
}
return null;
}
6. 设置index位置的对象为element,若操作成功,返回原对象,否则返回null;
public E set(int index, E element) {
if(index >= 0 && index < this.n && element != null){
E old = (E) this.table[index];
this.table[index] = element;
return old;
}
return null;
}
7. 在index位置插入element对象,若操作成功返回true,不能插入null;
//在index位置插入element对象,若操作成功返回true,不能插入null
public boolean add(int index, E element) {
if (element == null)
return false; //不能插入null
if (this.n == table.length){ //若数组满,则需要扩充顺序表容量
Object[] temp = this.table;
this.table = new Object[temp.length*2]; //重新申请一个容量更大的数组
for (int i = 0 ; i < temp.length ; i++){ //复制数组元素
this.table[i] = temp[i];
}
}
if (index < 0) //下标容错
index = 0;
if (index > this.n)
index = this.n;
for (int j = this.n - 1 ; j >= index ; j--){ //元素后移,平均移动n/2
this.table[j+1] = this.table[j];
}
this.table[index] = element;
this.n++;
return true;
}
@Override
public boolean add(E element) { //在顺序表最后插入element对象
return add(this.n , element);
}
8. 在顺序表最后插入element对象;
public boolean add(E element) { //在顺序表最后插入element对象
return add(this.n , element);
}
9. 移去index位置的对象,若操作成功,则返回被移去对象,否则返回null;
//移去index位置的对象,若操作成功,则返回被移去对象,否则返回null
public E remove(int index) {
if (this.n != 0 && index >= 0 && index < this.n){
E old = (E)this.table[index];
for (int j = index ; j < this.n-1 ; j++){ //元素前移,平均移动n/2
this.table[j] = this.table[j+1];
}
this.table[this.n-1] = null;
this.n--;
return old; //若操作成功,则返回被移去对象
}
return null; //未找到删除对象,操作不成功
}
10. 清空顺序表;
public void clear() { //清空顺序表
if (this.n != 0){
for (int i = 0 ; i < this.n ; i++) {
this.table[i] = null;
}
this.n = 0;
}
}
11. 返回显示所有元素值的字符串,形式为(,)。
public String toString(){ //返回显示所有元素值的字符串,形式为(,)
String str = "(";
if (this.n != 0){
for (int i = 0 ; i < this.n-1 ; i++){
str += this.table[i].toString()+",";
}
str += this.table[this.n - 1 ].toString();
}
return str+")";
}
12. 菜单。
public void mean(){ //菜单
System.out.println("————————————————欢迎使用顺序表———————————————");
System.out.println("| 01.创建顺序表 |");
System.out.println("| 02.判断顺序表是否为空 |");
System.out.println("| 03.返回顺序表长度 |");
System.out.println("| 04.返回下标为index的对象 |");
System.out.println("| 05.修改下标为index的对象 |");
System.out.println("| 06.在index位置插入对象 |");
System.out.println("| 07.在顺序表最后插入对象 |");
System.out.println("| 08.删除下标为index的对象 |");
System.out.println("| 09.打印顺序表 |");
System.out.println("| 10.清空顺序表 |");
System.out.println("| 11.退出使用顺序表 |");
System.out.println("————————————————欢迎使用顺序表———————————————");
}
六、顺序表LList的使用
public class list {
public static void main(String arg[]) throws IOException {
SeqList list = new SeqList();
Scanner sc = new Scanner(System.in);
int control = 0;
while (control == 0){
list.mean();
System.out.println("输入你的操作编号:");
int key = sc.nextInt();
control = Contorl(key , list);
}
System.out.println("————————————————————》》感谢使用");
}
//写一个方法Control,通过这个方法中的switch语句控制菜单完成各种选项的操作
public static int Contorl(int n , SeqList list){
Scanner sc = new Scanner(System.in);
switch (n){
case 1: //创建顺序表
int count; //控制要输入的元素个数
System.out.println("******》》输入的元素个数:");
count = sc.nextInt(); //输入元素个数
for(int i = 0 ; i <count ; i++){
System.out.printf("******》》输入的第%d个元素为:\n",i+1);
int elem = sc.nextInt();
list.add(elem);
}
System.out.println("******》》创建完成");
return 0;
case 2: //判断顺序表是否为空
if(list.isEmpty() == true ){
System.out.println("******》》顺序表为空《《******");
}else{
System.out.println("******》》顺序表不为空《《******");
}
return 0;
case 3: //返回顺序表长度
System.out.println("******》》顺序表长度为:"+list.length());
return 0;
case 4:
System.out.println("******》》顺序表长度为:"+list.length());
System.out.println("输入下标:");
int index1 = sc.nextInt();
System.out.println("******》》下标为"+ index1 + "的元素为:" + list.get(index1 - 1) );
return 0;
case 5:
System.out.println("******》》顺序表长度为:"+list.length());
System.out.println("******》》输入下标:");
int index2 = sc.nextInt();
System.out.println("******》》输入新的元素:");
int element = sc.nextInt();
list.set(index2 - 1,element);
System.out.println("******》》修改完成");
return 0;
case 6:
System.out.println("******》》顺序表长度为:"+list.length());
System.out.println("******》》输入下标:");
int index3 = sc.nextInt();
System.out.println("******》》输入插入的元素:");
int element1 = sc.nextInt();
list.add(index3 - 1,element1);
System.out.println("******》》插入成功");
return 0;
case 7:
System.out.println("******》》输入插入的元素:");
int element2 = sc.nextInt();
list.add( element2 );
System.out.println("******》》插入成功");
return 0;
case 8:
System.out.println("******》》输入下标:");
int index4 = sc.nextInt();
list.remove(index4 - 1);
System.out.println("******》》删除完成");
return 0;
case 9:
System.out.println("顺序表内的元素为:"+list.toString());
return 0;
case 10:
list.clear();
System.out.println("******》》清空完成");
case 11:
return 1;
default:
System.out.println("!!!没有该选项!!!");
}
return 1;
}
}