利用链表可以生成空链表,插入数据元素,删除数据元素,获取数据元素,重置数据元素。
1.首先声明一个线性表接口
package ch03;
public interface LList<T> {
boolean isEmpty();
int length();
T get(int i);
void set(int i,T x);
void insert(int i,T x);
void append(T x);
T remove(int i);
void removeAll();
}
2.定义结点类Node<T>,包括数据域和地址域两个成员变量,构造方法实例化结点,重写toString()方法获取结点的字符串描述。
package ch03;
public class Node<T> {// 单链表结点类,T指定结点的元素类型
// 成员变量
public T data; // 数据域,保存数据元素
public Node<T> next; // 地址域,引用后继结点
//构造方法
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
// 无参数的构造方法
public Node() {
this(null,null);
}
// 重写toString()方法
public String toString() {
return this.data.toString();
}
}
3.定义带头结点的单链表类SinglyList<T>类:
package ch03;
public class SinglyList <T> implements LList<T>{
private Node<T> head;//头指针,指向单链表的头结点
// 构造方法,创建空单链表
public SinglyList() {
this.head=new Node<T>();// 创建头结点,data和next均为null
}
// 构造方法,创建单链表,数据元素由values数组提供
public SinglyList(T[] values) {
this(); // 创建空单链表
Node<T> rear = this.head; // rear指向单链表最后一个结点
for (int i = 0; i < values.length; i++) { // 将values中的每个元素依次链接到单链表表尾
Node<T> p = new Node<T>(values[i], null); // 生成一个新结点p
rear.next = p; // 将新结点p链接到单链表表尾
rear = p; // rear指向单链表表尾
}
}
// 判断顺序表是否为空,若空返回true,否则返回false
@Override
public boolean isEmpty() {
if (head.next==null){
return true;
}
return false;
}
// 返回顺序表长度
@Override
public int length() {
int len=0;//单链表节点个数,即长度
Node<T> p = head.next; // p指向单链表第一个结点
while (p!=null){// 从第一个结点开始,直到表尾为止,即遍历单链表
len++;// 长度加1
p=p.next;// p指向下一个结点
}
return len;
}
// 返回顺序表中第i个元素,若i指定序号无效则返回null
@Override
public T get(int i) {
int j=0;//记录单链表结点个数
Node<T> p=head.next;// p指向单链表第一个结点
while (p!=null && j<i){// 遍历单链表,寻找第i个结点(p指向)
j++;//计数变量j+1
p=p.next;//p指向下一个节点
}
return (i>=0 && p!=null)? p.data:null;
}
// 设置顺序表中第i个元素为x(x为null除外),若i指定序号无效则抛出序号越界异常
@Override
public void set(int i, T x) {
if (x == null) {
throw new NullPointerException("插入的元素值不允许为空");
}
int j=0;//记录单链表结点个数
Node<T> p = head.next; // p指向单链表第一个结点
while (p != null && j < i) { // 遍历单链表,寻找第i个结点(p指向)
j++; // 计数变量j加1
p = p.next; // p指向下一个结点
}
if (i>=0 && p!=null){
p.data=x; // 设置顺序表中第i个元素为x
}else {
throw new IndexOutOfBoundsException("无第" + i + "个元素");
}
}
// 插入x作为第i元素,不能插入null
@Override
public void insert(int i, T x) {
if (x==null){
throw new NullPointerException("插入的元素不能为空");
}
// 下标容错
if (i < 0) {
i = 0;
}
if (i > length()) {
i = length();
}
// 寻找第i-1个结点
int j = 0; // 记录单链表结点个数
Node<T> p = head; // p指向单链表的头结点
while (p.next != null && j < i) { // 遍历单链表,寻找第i-1个结点(p指向)
j++; // 计数变量j加1
p = p.next; // p指向下一个结点
}
// 插入结点
Node<T> q=new Node<>(x,p.next);// 生成新结点q,且新结点q的地址域指向第i个结点
p.next=q;//p结点的地址域指向新结点q
}
@Override
public void append(T x) {
insert(Integer.MAX_VALUE, x); // 调用insert方法实现
}
// 删除第i个元素,若删除成功返回被删除数据元素,否则返回null
@Override
public T remove(int i) {
// 寻找第i-1个结点
int j = 0; // 记录单链表结点个数
Node<T> p = head; // p指向单链表的头结点
while (p.next != null && j < i) { // 遍历单链表,寻找第i-1个结点(p指向)
j++; // 计数变量j加1
p = p.next; // p指向下一个结点
}
if (i >= 0 && p.next != null) { // 找到了第i个结点,并使 p指向第i-1个结点
T elem = p.next.data; // 获取第i个结点的数据元素
p.next = p.next.next; // 删除第i个结点
return elem; // 返回第i个结点的数据
}
return null; // 没找到第i个结点,不能删除
}
// 删除顺序表中所用元素
@Override
public void removeAll() {
this.head.next=null;
}
// 返回顺序表中所有元素的描述字符串,形式为"(,)",覆盖Object类的toString()方法
public String toString() {
String str = "";
Node<T> p = head.next; // p指向单链表第一个结点
if (p!=null) {
str = "(";
while (p != null) { // 从第一个结点开始,直到表尾为止,即遍历单链表
str += p.data.toString() + ",";
p = p.next; // p指向下一个结点
}
str = str.substring(0, str.length() - 1);
str += ")";
} else {// 空表
str = "( )";
}
return str;
}
}
4.定义测试类,实现如下功能:通过输出的菜单项,进行功能选择并执行相应操作。
package ch03;
import java.util.Scanner;
public class ExSinglyList {
static Scanner r = new Scanner(System.in);
public static void main(String[] args) {
SinglyList<Integer> list = null;
int i;
int elem;
while (true) {
int choice=menu();
switch(choice){
case 1:
list=new SinglyList<Integer>();
System.out.print("生成单链表:");
System.out.println(list.toString());
break;
case 2:
System.out.print("插入的数据元素:");
elem=r.nextInt();
System.out.print("插入数据元素的位置(0-"+list.length()+"):");
i=r.nextInt();
list.insert(i, elem);
System.out.println("插入数据元素后单链表:"+list.toString());
break;
case 3:
System.out.print("删除第几个数据元素?(0-"+(list.length()-1)+"):");
i=r.nextInt();
elem=list.remove(i);
System.out.println("被删除的数据元素:"+elem);
System.out.println("删除数据元素后单链表:"+list.toString());
break;
case 4:
System.out.print("获取第几个数据元素?(0-"+(list.length()-1)+"):");
i=r.nextInt();
elem=list.get(i);
System.out.println("单链表的数据元素:"+list.toString());
System.out.println("第"+i+"个数据元素:"+elem);
break;
case 5:
System.out.print("修改第几个数据元素?(0-"+(list.length()-1)+"):");
i=r.nextInt();
System.out.print("修改为的数据元素:");
elem=r.nextInt();
list.set(i, elem);
System.out.println("修改数据元素后单链表:"+list.toString());
break;
case 6:
System.exit(0);
}
}
}
// 生成菜单并选择相应操作
public static int menu() {
int c = 0;
do {
System.out.println("\n*************************");
System.out.println(" 1.生成空单链表");
System.out.println(" 2.插入数据元素");
System.out.println(" 3.删除数据元素");
System.out.println(" 4.获取数据元素");
System.out.println(" 5.重置数据元素");
System.out.println(" 6.谢谢使用系统");
System.out.println("*************************");
System.out.print("请选择(输入数字1~6):");
c = r.nextInt();
r.nextLine();
} while (c < 1 || c > 6);
return c;
}
}