数据结构:单链表的设计
单链表的设计:
第一步:需要设计好一个结点:怎么设计呢?
- 用一个类来模拟一个结点:
- 这里为每个结点赋予一个实际意义,便于理解,在这里把一个结点赋予为一个英雄
- 英雄包括:num 编号、name 姓名 、nickname 昵称 等属性。

第二步:需要把列表连起来,形成一个链表。为链表设计[增删改查等]方法
- 插入功能:根据编号进行插入,即使插入时编号的顺序是乱的,最后也可以根据编号的大小来进行显示
- 删除功能:找到待删除元素的前一个元素,找到就删除。找到编号->修改标记->删除结点
- 修改功能: 根据编号来修改,找到编号->修改标记->修改结点内容
- 查看功能:遍历显示单链表中所有的结点

第三步:测试单链表功能是否正常可用

第四步:完整包含注释的代码如下:
package DataSturcture.linkedlist;
/**
* 单链表的小案例:
* 用一个类来模拟一个结点:每个结点赋予一个意义,一个节点表示一个水浒英雄
* 用一个类来模拟一整个单链表:一个单链表表示你创建的水浒英雄,可以对水浒英雄进行管理
*/
public class SinglelinkedlistTest {
public static void main(String[] args) {
System.out.println("===================插入功能测试=======================");
Node node1 = new Node(11,"宋江","及时雨");
Node node2 = new Node(4,"林冲","豹子头");
Node node3 = new Node(2,"鲁智深","花和尚");
Node node4 = new Node(1,"武松","打虎英雄");
Node node5 = new Node(3,"小卢","小尾巴");
Node node6 = new Node(5,"吴用","智多星");
SingleLinkedList sll = new SingleLinkedList();
sll.addPlus(node1);
sll.addPlus(node2);
sll.addPlus(node3);
sll.addPlus(node4);
sll.addPlus(node5);
sll.addPlus(node6);
sll.show();
System.out.println("===================修改功能测试=======================");
Node node = new Node(3,"卢俊义","玉麒麟");
// SingleLinkedList sll2 = new SingleLinkedList();
sll.update(node);
sll.show();
System.out.println("===================删除功能测试=======================");
sll.delete(5);
sll.show();
}
}
/**
* 用一个类来模拟一个单链表:
* 一个单链表应该包括:1. 插入功能:
* 2. 删除功能:
* 3. 修改功能:根据编号来修改
* 4. 查看功能:遍历显示单链表中所有的结点
*/
class SingleLinkedList{
/**
* 先初始化一个头节点, 头节点不要动, 不存放具体的数据
*/
private static final Node head = new Node(0, "", "");
/**
* 插入方式1[不推荐]:当不考虑编号顺序时,来一个插入一个,和数组的插入几乎一样,没有实现随机插入
* 思路:1.遍历一遍单链表,让temp找到当前链表的最后节点
* 2.把n链接到最后这个节点的 next下一个结点
*/
public void add(Node n) {
// 因为 head 节点不能动,因此我们需要一个辅助遍历 temp
Node temp = head;
/**
* while循环的作用是:从头结点开始一直遍历到最后,让temp指向单链表的最后一个结点
*/
while (true) {
// 到了链表的最后就结束循环
if (temp.next == null) {
break;
}
// 如果没有找到最后, 继续将 temp 后移
temp = temp.next;
}
/**
* 当退出 while 循环时,temp 就指向了链表的最后
* 然后把n链接到最后这个节点的 next下一个结点
*/
temp.next = n;
}
/**
* 插入方式2[推荐]:根据编号进行插入,即使插入时编号的顺序是乱的,最后也可以根据编号的大小来进行显示,实现了随机插入
*
*/
public void addPlus(Node n) {
// 因为单链表,因为我们找的 temp 是位于 添加位置的前一个节点,否则插入不了
Node temp = head;
// isExist标志添加的编号是否存在,如存在则不能重复添加
boolean isExist = false;
/**
* 1. 循环结束后,temp就已经找到和num合适的插入位置,并且已经知道了要添加节点的编号是否存在
*/
while (true) {
if (temp.next == null) {
break;
}
// 位置找到啦,就在 temp 的后面插入
if (temp.next.num > n.num) {
break;
} else if (temp.next.num == n.num) {
isExist = true;
break;
}
// temp逐个后移,逐个判断
temp = temp.next;
}
/**
* 2. 存在:添加
* 不存在:不添加
*/
if (isExist) {
System.out.printf("准备插入的%s的编号 %d 已经存在了, 不能重复加入了哦~\n", n.name,n.num);
} else {
// 添加:1.添加位置的前一个节点的next断开,连接上新来的结点的next 2.再把新来的结点给添加位置的前一个节点的next
n.next = temp.next;
temp.next = n;
}
}
/**
* 修改节点的信息: 根据 num 编号来修改,即 num 编号不能改
*/
public void update(Node n) {
// 链表为空不用修改
if (head.next == null) {
System.out.println("链表为空~");
return;
}
// 头结点不能动,设置辅助结点Node
Node temp = head.next;
// 是否找到了该节点
boolean findNode = false;
while (true) {
if (temp.next == null) {
break;
}
// 找到编号,修改标记
if (temp.num == n.num) {
findNode = true;
break;
}
// 没找到就一个一个继续往后找
temp = temp.next;
}
// 找到了就修改
if (findNode) {
String originalName = temp.name;
temp.name = n.name;
temp.nickname = n.nickname;
System.out.printf("编号:%d的%s已修改为: %s -> %s\n",n.num,originalName,n.name,n.nickname);
} else { // 没有找到
System.out.printf("没有找到%s编号 %d的节点,不能修改哦~\n",n.name, n.num);
}
}
/**
* 删除节点:
* 1. 输入要删除结点的编号num,我们去匹配这个num在链表中是否有temp与之相等
*/
public void delete(int num) {
Node temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
// 找到的待删除节点的前一个节点 temp flag = true;
if (temp.next.num == num) {
flag = true;
break;
}
// 逐个继续向后找
temp = temp.next;
}
if (flag) {
// 找到了,删除
temp.next = temp.next.next;
System.out.printf("编号:%d已删除!\n",num);
} else {
System.out.printf("要删除的编号 %d 结点不存在\n", num);
}
}
/**
* 显示链表[遍历]
*/
public void show() {
// 判断链表是否为空
if (head.next == null) {
System.out.println("链表为空~");
return;
}
// 因为头结点不能动,因此我们需要一个辅助变量来遍历
Node temp = head.next;
while (true) {
// 判断是否到链表最后,注意,这里不能是temp.next为空,都则最后一个结点无法打印就会退出循环
if (temp == null) {
break;
}
// 输出节点的信息
System.out.println(temp);
temp = temp.next;
}
}
}
/**
* 用一个类来模拟一个结点:
* 单链表的结点包括:1. num 编号
* 2. name 姓名
* 3. nickname 昵称
* 4. next指针,数据类型应为Node类型,因为它指向的下一个结点仍然是一个Node
*/
class Node{
public int num;
public String name;
public String nickname;
/**
* 定义一个指针,指向下一个结点的信息
*/
public Node next;
public Node(int num, String name, String nickname) {
this.num = num;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "HeroNode [num=" + num + ", name=" + name + ", nickname=" + nickname + "]";
}
}

浙公网安备 33010602011771号