目录
线性表的定义
概述:由n个数据元素(结点)a1,a2,a3...a[n]组成的有限序列,数据元素个数n为表的长度,n为零时称为空表。
非空线性表逻辑特征:
- 有且仅有一个开始元素a1,它没有前趋,仅有一个直接后继a2
- 有且仅有一个终端元素a[n],它没有后继,仅有一个直接前趋
- 其余元素a[i](2≤i≤n-1)称为内部元素,它们都有且仅有一个直接前趋a[i-1]和一个直接后继a[i+1]
线性表的顺序存储
概述:将线性表的数据元素按其逻辑次序依次存入一组地址连续的存储单元里。
位置关系:
假设线性表中所有元素类型相同,且每个元素占用d个存储单元。
LOC(a1)是线性表的第一个元素a1的存储位置,称为基地址。
特点:
- 在逻辑关系上相邻的两个元素在物理位置上也是相邻的
- 只要知道基地址和每个元素占用的单元数(元素的大小),就可求出任一元素的存储地址,所以顺序表是一种随机存取结构
线性表的基本运算
插入运算
概述:在线性表的第i-1个元素和第i个元素之间插入一个新元素x,使长度为n的线性表变为长度为n+1的线性表。
向后移动元素,移动次数:n-i+1 (n为表长,i为插入元素的位置)
平均时间复杂度:O(n)
删除运算
概述:将表中第i (1≤i≤n)个元素删除,使长度为n的线性表变为长度为n-1的线性表。
向前移动元素,移动次数:n-i (n为表长,i为删除元素的位置)
平均时间复杂度:O(n)
基本运算实现
//线性表的顺序存储
public class SeqList {
//表空间大小
int listSize = 100;
//类型未知,设定为Object,数组data存放表结点
Object[] data = new Object[listSize];
//线性表的当前表长:实际存储元素的个数
int count = 0;
//置空表:表中所有元素都置为null
public void InitList() {
for (int i = 0; i < listSize; i++) {
data[i] = null;
}
count = 0;
}
//求表长:返回表中元素个数
public int ListLength() {
return count;
}
//查找:取表中第i个元素
public Object GetNode(int i) {
//判断是否索引越界
if (i < 1 || i > listSize) {
System.out.println("position error!");
return null;
} else {
return data[i - 1];
}
}
//查找:查找第一个值为x的元素,并返回其位置
public int LocateNode(Object x) {
int index = -1;
for (int i = 0; i < listSize; i++) {
if (data[i].equals(x)) {
index = i;
break;
}
}
if (index != -1)
index++;
return index;
}
//插入:在顺序表L中第i个位置之前插入一个新元素x
public void InsertList(int i, int x) {
//判断插入的位置是否合法
if (i < 1 || i > listSize) {
System.out.println("position error!");
}
//判断表的长度是否超出限制
if (count >= listSize) {
System.out.println("overflow!");
}
//循环插入位置后面的元素
for (int j = count - 1; j >= i - 1; j--) {
//从最后一个元素开始逐一往后移
data[j + 1] = data[j];
}
//插入新元素x
data[i - 1] = x;
//表中实际长度加1
count++;
}
//删除:删除第i个元素,并返回该元素
public Object deleteList(int i) {
//判断删除的位置是否合法
if (i < 1 || i > count) {
System.out.println("position error!");
System.exit(0);
}
//获取被删除元素
Object x = data[i - 1];
//从被删除元素开始,向前循环移动后面的元素
for (int j = i; j <= count; j++) {
data[j - 1] = data[j];
}
//表中实际长度减1
count--;
return x;
}
}
测试:
public class SeqListTest {
public static void main(String[] args) {
SeqList sl = new SeqList();
//置空表
sl.InitList();
System.out.println(sl.data[0] + " " + sl.data[99]);
System.out.println("length:" + sl.data.length);
System.out.println("count:"+sl.count);
System.out.println();
//插入元素
sl.InsertList(1, 2);
sl.InsertList(2, 4);
sl.InsertList(3, 6);
sl.InsertList(4, 8);
//遍历表中元素
System.out.print("表中元素有:");
for (int i = 0; i < sl.count; i++) {
System.out.print(sl.data[i] + " ");
}
System.out.println();
//求表长
int count = sl.ListLength();
System.out.println("元素个数:" + count);
System.out.println();
//查找(按位置)
Object o = sl.GetNode(4);
System.out.println("第4个元素:" + o);
System.out.println();
//查找(按值)
Object o1 = sl.LocateNode(6);
System.out.println("值为6的下标:" + o1);
System.out.println();
//删除
Object o2 = sl.deleteList(3);
System.out.println("删除的元素为:" + o2);
System.out.print("表中元素:");
for (int i = 0; i < sl.count; i++) {
System.out.print(sl.data[i] + " ");
}
System.out.println();
//求表长
int count1 = sl.ListLength();
System.out.println("元素个数:" + count1);
}
}
运行结果:
其他运算
线性表逆置
说明:线性表为 (a1,a2,...,a(n)),逆置之后为 (a(n),a(n-1),...,a1),以顺序表存储方式存储。
基本思想:以表长的一半控制循环次数,将表中最后一个元素同顺数第一个数交换,将倒数第二个元素同顺数第二个元素交换,以此类推,直至交换完为止。
代码实现:
public class SeqListTest { public static void main(String[] args) { SeqList sl = new SeqList(); //置空表 sl.InitList(); //插入元素 sl.InsertList(1, 2); sl.InsertList(2, 4); sl.InsertList(3, 6); sl.InsertList(4, 8); sl.InsertList(5, 10); sl.InsertList(6, 12); //遍历初始元素 System.out.println("初始元素:"); for (int i = 0; i < sl.count; i++) { System.out.print(sl.data[i] + " "); } System.out.println(); System.out.println(); //逆置 Converts(sl); //遍历逆置后的元素 System.out.println("逆置后的元素:"); for (int i = 0; i < sl.count; i++) { System.out.print(sl.data[i] + " "); } } //线性表逆置 public static Object[] Converts(SeqList seqList) { Object x; //获取表长的一半 int k = seqList.count / 2; for (int i = 0; i < k; i++) { //获取前面元素的值,赋值给x x = seqList.data[i]; //将后面对应的值赋值给前边的元素 seqList.data[i] = seqList.data[seqList.count - i - 1]; //将x的值赋值给后边的元素 seqList.data[seqList.count - i - 1] = x; } return seqList.data; } }
运行结果:
温馨提示:
线性表逆置该方法里for语句里执行的三条基本语句是交换两个数值的常用语句,这个点可以记死,固定写法,非常好用。
顺序表找最大最小值
说明:找出最大值和最小值的元素及其所在位置。
代码实现:
public class SeqListTest { public static void main(String[] args) { SeqList sl = new SeqList(); //置空表 sl.InitList(); //插入元素 sl.InsertList(1, 7); sl.InsertList(2, 4); sl.InsertList(3, 12); sl.InsertList(4, 24); sl.InsertList(5, 18); sl.InsertList(6, 6); //遍历初始元素 System.out.println("初始元素:"); for (int i = 0; i < sl.count; i++) { System.out.print(sl.data[i] + " "); } System.out.println(); System.out.println(); //获取最大值和最小值及其索引 int[] ints = MaxAndMin(sl); System.out.println("最大值索引:" + ints[0] + " 最大值:" + ints[1]); System.out.println("最小值索引:" + ints[2] + " 最小值:" + ints[3]); } //找出最大值和最小值,及其下标 public static int[] MaxAndMin(SeqList seqList) { //定义一个数组,存放最大值、最小值及其索引 int[] index = new int[4]; //设置最大值和最小值的索引值 int maxIndex = 0; int minIndex = 0; //获取第一个元素值,假定为最大和最小值 int max = (int) seqList.data[0]; //强制类型转换 int min = (int) seqList.data[0]; for (int i = 1; i < seqList.count; i++) { //判断如果元素值大于设定的最大值,就获取该索引,反之获取最小值的索引 if ((int) seqList.data[i] > max) { maxIndex = i; max = (int) seqList.data[i]; } else if ((int) seqList.data[i] < min) { minIndex = i; min = (int) seqList.data[i]; } } //给数组赋值 //最大值索引及其值 index[0] = maxIndex; index[1] = max; //最小索引及其值 index[2] = minIndex; index[3] = min; return index; } }
运行结果:
温馨提示:
找最大最小值这种问题,有一种固定的写法,打擂台法,其基本思想就是设定第一个元素为最大或者最小值,然后再循环依次比较,如果数组中有比最大值还大的元素,或者比最小值还要小的元素,就给设定的最大最小值重新赋值,循环结束后的值,就是想要的最大最小值。