单链表:每个结点中只包含一个指针域的链表。
单链表结构如下:
单链表与顺序存储结构的对比:
模拟单链表:
public class LinkList<E> {
private Node<E> head; //头结点
private int count; //节点个数
/**
* 结点
*/
private class Node<E> {
E data; // 节点内容,数据内容
Node<E> next;// 下一个节点地址引用,后继地址
public Node(E data, Node<E> next) {
this.data = data;
this.next = next;
}
}
/**
* 线性表的初始化
*/
public LinkList() {
head = new Node<E>(null, null); //不是head=null;
count = 0;
}
/**
* 判断线性表是否为空
*/
public boolean IsEmpty() {
if (count == 0) {
System.out.println("表为空!");
return true;
} else {
System.out.println("表不为空!");
return false;
}
//return count==0;
}
/**
* 清空线性表(自己编写的)
*/
public void ClearList() {
Node<E> node;
while (count != 0) {
node = head.next;
head.next = node.next;
node = null;
count--;
}
System.out.println("线性表已清空!");
}
/**
* 清空线性表(书中改写)
*/
public void ClearList2() {
Node<E> q, p;
q = head.next;
while (q != null) {
p = q.next;
q = null;
q = p;
count--;
}
head.next = null;
System.out.println("线性表已清空!");
}
/**
* 获取第i个结点(包括第0个结点,头结点)
* 获取结点值只需要GetNode(i).data即可,不再写方法了
*/
public Node<E> GetNode(int i) {
if (i < 0 || i > count) {
throw new RuntimeException("元素位置错误!");
} else if (i == 0) {
return head;
} else {
Node<E> node = head.next; // 第1个节点,
for (int k = 1; k < i; k++) {
node = node.next;
}
return node;
}
}
/**
* 获取第i个结点的数据(包括头结点)
*/
public E GetData(int i) {
return GetNode(i).data;
}
/**
* 查找元素,0代表查找失败
*/
public int LocateElem(E e) {
Node<E> node;
node = head.next;
if (node.data == e)
return 1;
for (int k = 1; k < count; k++) {
node = node.next;
if (node.data == e)
return k + 1;
}
System.out.println("查找失败!");
return 0;
}
/**
* 第i个位置插入新的元素
*/
public void ListInsert(int i, E e) {
if (i < 1 || i > count + 1) {
throw new RuntimeException("插入位置错误!");
} else {
Node<E> newNode = new Node<E>(e, null); // 创建一个节点
newNode.next = GetNode(i - 1).next; //当插入的元素在链表中已经存在的时候,需要重新构建节点关系
GetNode(i - 1).next = newNode;
count++;
System.out.println("插入成功!");
}
}
/**
* 删除第i个位置元素,并返回其值
*/
public E ListDelete(int i) {
if (i < 1 || i > count)
throw new RuntimeException("删除位置错误!");
Node<E> node = GetNode(i);
E e = node.data;
GetNode(i - 1).next = node.next; // 将当前节点的下一个节点,关联到当前节点的上一个节点完成删除。
node = null;
count--;
System.out.println("删除成功!");
return e;
}
/**
* 获取线性表长度
*/
public int ListLength() {
return count;
}
/**
* 整表创建,头插法
*/
public LinkList<Integer> CreateListHead(int n) {
LinkList<Integer> list1 = new LinkList<Integer>();
Node<Integer> node, lastNode;
for (int i = 0; i < n; i++) {
int data = (int) (Math.random() * 100); //生成100以内的随机数
node = new Node<Integer>(data, null);
node.next = (LinkList<E>.Node<Integer>) list1.head.next;
list1.head.next = (LinkList<Integer>.Node<Integer>) node;
list1.count++;
}
return list1;
}
/**
* 整表创建,尾插法
*/
public LinkList<Integer> CreateListTail(int n) {
LinkList<Integer> list2 = new LinkList<Integer>();
Node<Integer> node, lastNode;
lastNode = (LinkList<E>.Node<Integer>) list2.head;
for (int i = 0; i < n; i++) {
int data = (int) (Math.random() * 100); //生成100以内的随机数
node = new Node<Integer>(data, null);
lastNode.next = node;
lastNode = node;
list2.count++;
}
return list2;
}
}
基本数据类型测试
public class LinkListTest1 {
public static void main(String[] args) {
LinkList<Integer> nums = new LinkList<Integer>();
nums.IsEmpty();
System.out.println("——————————插入1到5,并读取内容——————————");
for (int i = 1; i <= 5; i++)
nums.ListInsert(i, 2*i);
nums.IsEmpty();
int num;
for (int i = 1; i <= 5; i++) {
num = nums.GetData(i);
System.out.println("第" + i + "个位置的值为:" + num);
}
System.out.println("——————————查找0、2、10是否在表中——————————");
System.out.print("0的位置:");
System.out.println(nums.LocateElem(0));
System.out.print("2的位置:");
System.out.println(nums.LocateElem(2));
System.out.print("10的位置:");
System.out.println(nums.LocateElem(10));
System.out.println("——————————删除2、10——————————");
num = nums.ListDelete(1);
System.out.println("已删除:" + num);
num = nums.ListDelete(4);
System.out.println("已删除:" + num);
System.out.println("当前表长:" + nums.ListLength());
for (int i = 1; i <= nums.ListLength(); i++) {
num = nums.GetData(i);
System.out.println("第" + i + "个位置的值为:" + num);
}
nums.ClearList();
nums.IsEmpty();
}
}
引用类型测试
public class LinkListTest2 {
public static void main(String[] args) {
LinkList<Student> students = new LinkList<Student>();
students.IsEmpty();
System.out.println("——————————插入1到5,并读取内容——————————");
Student[] stus = {
new Student("小A", 11),
new Student("小B", 12),
new Student("小C", 13),
new Student("小D", 14),
new Student("小E", 151)
};
for (int i = 1; i <= 5; i++)
students.ListInsert(i, stus[i - 1]);
students.IsEmpty();
Student stu;
for (int i = 1; i <= 5; i++) {
stu = students.GetData(i);
System.out.println("第" + i + "个位置为:" + stu.name);
}
System.out.println("——————————查找小A、小E、小龙是否在表中——————————");
System.out.print("小A的位置:");
stu = stus[0];
System.out.println(students.LocateElem(stu));
System.out.print("小E的位置:");
stu = stus[4];
System.out.println(students.LocateElem(stu));
System.out.print("小龙的位置:");
stu = new Student("小龙", 11);
System.out.println(students.LocateElem(stu));
System.out.println("——————————删除小E、小B——————————");
stu = students.ListDelete(2);
System.out.println("已删除:" + stu.name);
stu = students.ListDelete(4);
System.out.println("已删除:" + stu.name);
System.out.println("当前表长:" + students.ListLength());
for (int i = 1; i <= students.ListLength(); i++) {
stu = students.GetData(i);
System.out.println("第" + i + "个位置为:" + stu.name);
}
students.ClearList();
students.IsEmpty();
}
}
class Student {
public Student(String name, int age) {
this.name = name;
this.age = age;
}
String name;
int age;
}
单链表:操作对象的引用来改变节点间相互连接的状态