数据结构:线性表及Java实现
声明:概念方面不清楚的读者,可以通过书籍或者网络搜索相关名词解释,本文重点关注在代码实现层面
一 序言
本文内容:先讲解线性表基础知识,然后使用数组和链表实现线性表。
二 线性表基本知识
1 线性表:由零个或多个数据元素组成的有序序列。
2 线性表中每个节点最多只有一个前驱节点和后继节点,头节点没有前驱节点,尾节点没有后继节点。
图1 线性表结构
如图1所示,节点个数为n,节点a1是头节点,它没有前驱节点,它的后继节点是a2,an为尾节点,它没有后继节点,它的前驱节点为a(n-1),a2的前驱节点为a1,后继节点为a3(图中未画出)。从图1可以看出,线性表各节点的逻辑结构直观上可以看成各个节点相连接,形成一条链。
注意:图1中的箭头并不表示指针,笔者只是想表达它们的存储关系是链式的
3 线性表存储结构
线性表在内存中存储结构包含两种形式:
a) 顺序存储,存储单元连续,前驱节点和后继节点所存储的内存是紧靠着的,如图2所示
b) 链式存储,存储单元不一定连续,前驱节点和后继节点所存储的内存非紧靠着的,此时需要通过一个指针(Java中称为引用)指向来串接,如图3所示
图2 内存连续
图3 内存不连续
从图2可以看出,对于内存连续的线性表,通过前驱节点向后移动一个节点(由当前节点类型所占空间大小决定)即可找到其后继节点;
从图2可以看出,对于内存不连续的线性表,需要通过一个辅助手段找到节点的后继节点,即添加一个next指针(Java中成为对应引用,类似指针的概念),并通过该next指针找到其后继节点,灰色块表示,它们可能是内存连续的或者相隔若干个节点;
4 抽象数据类型
抽象数据类型是对同种类型数据及对该种类型数据所做操作的抽象。
数据类型包括:原子数据类型和结构数据类型。原子类型不可分割,结构类型由结构类型和原子类型组合而成,它不是最小数据单元。
数据操作包括:初始化操作,清空操作,增加数据,删除数据,修改数据,查询数据,判断线性表是否为空和判断线性表大小等操作。
三 数组实现线性表
package com.datastruct.linear;
/**
* Description: 【数据结构-线性表】数组实现方案
*
* @author guodong
* @date 2020/3/28 22:41
*/
public class ArrayLinear {
/**
* 定义线性表大小,不考虑扩容的情况
*/
private static int ARRAY_LEN = 10;
/**
* 记录线性表当前大小
*/
private static int CURRENT_SIZE = 0;
/**
* 初始化数组,申请连续的空间
*/
private static int[] arrayList;
public static void main(String[] args) {
createList();
delete(0);
insert(0, 10);
printValue(arrayList);
insert(2, 12);
printValue(arrayList);
insert(1, 11);
printValue(arrayList);
int delete = delete(1);
System.out.println("【删除】结果:" + delete);
printValue(arrayList);
int update = update(0, 100);
System.out.println("【更新】结果:" + update);
printValue(arrayList);
int get = get(11);
System.out.println("【查询】结果:" + get);
get = get(8);
System.out.println("【查询】结果:" + get);
}
/**
* 初始化线性表
*/
private static void createList() {
arrayList = new int[ARRAY_LEN];
}
/**
* 判断线性表是否为空
*/
private static boolean isEmpty() {
return CURRENT_SIZE == 0;
}
/**
* 判断是否达到容量上限
*/
private static boolean isFull() {
return CURRENT_SIZE == ARRAY_LEN - 1;
}
/**
* 添加数值到指定位置,从指定位置开始,
* 将其后的数据往后移动一位,然后将数据放到指定位置
*
* @param local 指定位置
* @param value 数值
* @return void
*/
private static void insert(int local, int value) {
if (isFull()) {
System.out.println("线性表容量达到上限");
return;
}
if (local > CURRENT_SIZE) {
throw new ArrayIndexOutOfBoundsException();
}
if (local == CURRENT_SIZE) {
arrayList[local] = value;
CURRENT_SIZE++;
return;
}
for (int l = CURRENT_SIZE - 1; l > local; l--) {
arrayList[l + 1] = arrayList[l];
}
arrayList[local] = value;
}
/**
* 删除指定位置的值,将其后面的数据往前移动一位,返回原来的值
*
* @param local 位置
* @return int
*/
private static int delete(int local) {
if (isEmpty()) {
System.out.println("线性表为空");
return -1;
}
if (local < 0 || local > CURRENT_SIZE) {
throw new ArrayIndexOutOfBoundsException();
}
// 缓存删除前的内容
int oldValue = arrayList[local];
// 删除元素
arrayList[local] = 0;
// 将其后面数据往前移动
for (int l = local; l < CURRENT_SIZE; l++) {
arrayList[local] = arrayList[local + 1];
}
return oldValue;
}
/**
* 修改指定位置的数值,并返回修改前的值
*
* @param local 位置
* @param value 修改后的值
* @return int
*/
private static int update(int local, int value) {
if (isEmpty()) {
System.out.println("线性表为空");
return -1;
}
if (local < 0 || local > ARRAY_LEN) {
throw new ArrayIndexOutOfBoundsException();
}
int oldValue = arrayList[local];
arrayList[local] = value;
return oldValue;
}
/**
* 获取指定位置数值
*
* @param local 位置
* @return int
*/
private static int get(int local) {
if (isEmpty()) {
System.out.println("线性表为空");
return -1;
}
if (local < 0 || local > ARRAY_LEN) {
throw new ArrayIndexOutOfBoundsException();
}
return arrayList[local];
}
/**
* 数组打印
*
* @param array 线性表
* @return void
*/
private static void printValue(int[] array) {
for (int index = 0; index < array.length; index++) {
System.out.print("array[" + index + "]= " + array[index] + " ");
}
System.out.println("");
}
}
四 链表实现线性表
package com.datastruct.linear;
/**
* Description: 【数据结构-线性表】链表实现方案
*
* @author guodong
* @date 2020/3/28 22:46
*/
public class LinkedLinear {
/**
* 头节点,不存储任何数据,标志链表起始位置
*/
private static Node root;
public static void main(String[] args) {
createList();
printValue(root);
insert(1, new Node(11));
printValue(root);
insert(2, new Node(22));
printValue(root);
Node delete = delete(1);
System.out.println("【删除】结果:" + (delete == null ? "null" : delete.getValue()));
printValue(root);
Node update = update(1, new Node(122));
System.out.println("【更新】结果:" + (update == null ? "null" : update.getValue()));
printValue(root);
Node node = get(1);
System.out.println("【查询】结果:" + (node == null ? "null" : node.getValue()));
}
/**
* 初始化链表
*/
private static void createList() {
root = new Node(0);
}
/**
* 判断线性表是否为空
*/
private static boolean isEmpty() {
return root == null;
}
/**
* 插入节点
*
* @param local 位置
* @param node 数据节点
* @return void
*/
private static void insert(int local, Node node) {
if (isEmpty()) {
createList();
}
Node tmp = root;
int size = 0;
while (tmp.getNext() != null) {
size++;
if (size == local) {
tmp.setNext(node);
return;
}
tmp = tmp.getNext();
}
tmp.setNext(node);
}
/**
* 删除指定位置元素
*
* @param local 位置
* @return com.datastruct.linear.Node
*/
private static Node delete(int local) {
if (isEmpty()) {
System.out.println("线性表为空");
return null;
}
Node tmp = root;
int size = 0;
while (tmp != null) {
if (size++ == local - 1) {
Node next = tmp.getNext();
if (next != null) {
tmp.setNext(next.getNext());
} else {
System.out.println("没有指定元素");
}
return next;
}
tmp = tmp.getNext();
}
System.out.println("没有指定元素");
return null;
}
/**
* 更新指定位置元素
*
* @param local 位置
* @param node 更改后的内容
* @return com.datastruct.linear.Node
*/
private static Node update(int local, Node node) {
if (isEmpty()) {
System.out.println("线性表为空");
return null;
}
Node tmp = root;
int size = 0;
while (tmp != null) {
if (size++ == local) {
Node oldValue = tmp;
tmp.setValue(node.getValue());
return oldValue;
}
tmp = tmp.getNext();
}
System.out.println("没有指定元素");
return null;
}
/**
* 查询节点
*
* @param local 指定位置
* @return com.datastruct.linear.Node
*/
private static Node get(int local) {
if (isEmpty()) {
System.out.println("线性表为空");
return null;
}
Node tmp = root;
int size = 0;
while (tmp != null) {
if (size++ == local) {
return tmp;
}
tmp = tmp.getNext();
}
System.out.println("没有指定元素");
return null;
}
/**
* 数组打印
*
* @param root 线性表
* @return void
*/
private static void printValue(Node root) {
int len = 0;
while (root != null) {
System.out.print("node[" + len++ + "]= " + root.getValue() + " ");
root = root.getNext();
}
System.out.println("");
}
}
class Node {
private int value;
private Node next;
public Node(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setNext(Node next) {
this.next = next;
}
public Node getNext() {
return next;
}
}