流程:
单链表的应用实例
1. 单链表的建立:
使用带head头的单向链表实现 –水浒英雄排行榜管理
完成对英雄人物的增删改查操作, 注: 删除和修改,查找
第一种方法在添加英雄时,直接添加到链表的尾部
第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
1.1第一种方法:添加英雄时,直接添加到链表的尾部
添加(创建)
1.先创建一个head 头节点, 作用就是表示单链表的头
2.后面我们每添加一个节点,就直接加入到 链表的最后
遍历:
1.通过一个辅助变量遍历,帮助遍历整个链表
- 首先定义数据节点信息
public class Node {
private int num;
private String name;
private String nickname;
private Node next;
public Node(int num, String name, String nickname) {
this.num = num;
this.name = name;
this.nickname = nickname;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"num=" + num +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
- 定义链表规则
public class SingeLinkedList {
//先创建一个head 头节点, 作用就是表示单链表的头
private Node firstNode = new Node(0, "", "");
//后面我们每添加一个节点,就直接加入到 链表的最后
//思路 当不考虑编号的顺序的时候
//1.找到当前链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(Node node) {
//1.找到最后一个节点,每次查询元素都要从头开始
Node temp = firstNode;
while (true) {
if (temp.getNext() == null) {
break;
} else {
temp = temp.getNext();
}
}
//2.将最后这个节点的next指向新的节点
temp.setNext(node);
}
//通过一个辅助变量遍历,帮助遍历整个链表
public void list() {
//先判断链表是否为空
if (firstNode.getNext() == null) {
System.out.println("链表为空");
} else {
//因为头节点不能动 因此需要一个辅助变量
Node temp = firstNode;
while (true) {
//判断链表是否到最后
if (temp.getNext() == null) {
break;
} else {
//输出节点的信息
System.out.println(temp.getNext());
//将 temp 后移
temp = temp.getNext();
}
}
}
}
}
- 测试
public class DemoNode {
public static void main(String[] args) {
Node one = new Node(1,"宋江","及时雨");
Node two = new Node(2,"卢俊义", "玉麒麟");
Node three = new Node(3,"吴用","智多星");
Node four = new Node(4,"公孙胜","入云龙");
Node five = new Node(5,"关胜","大刀");
SingeLinkedList singeLinkedList = new SingeLinkedList();
singeLinkedList.add(four);
singeLinkedList.add(five);
singeLinkedList.add(one);
singeLinkedList.add(three);
singeLinkedList.add(two);
singeLinkedList.list();
}
}
1.2 第二种方法:添加英雄时,按照英雄排名排序
自己方法:
1.创建列表,盛放链表所有信息
2.使用collections.sort排序,使用lambda表达式重写Comparator比较器,根据num排序升序
3.stream流forEach遍历array
import java.util.*;
public class SingeLinkedList02 {
//先创建一个head 头节点, 作用就是表示单链表的头
private Node firstNode = new Node(0, "", "");
//后面我们每添加一个节点,就直接加入到 链表的最后
//思路 当不考虑编号的顺序的时候
//1.找到当前链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(Node node) {
//1.找到最后一个节点,每次查询元素都要从头开始
Node temp = firstNode;
while (true) {
if (temp.getNext() == null) {
break;
} else {
temp = temp.getNext();
}
}
//2.将最后这个节点的next指向新的节点
temp.setNext(node);
}
//通过一个辅助变量遍历,帮助遍历整个链表
public void list() {
//创建列表,盛放链表所有信息
List<Node> array = new ArrayList<>();
Map<Integer,Node> map = new HashMap<>();
//先判断链表是否为空
if (firstNode.getNext() == null) {
System.out.println("链表为空");
} else {
//因为头节点不能动 因此需要一个辅助变量
Node temp = firstNode;
while (true) {
//判断链表是否到最后
if (temp.getNext() == null) {
break;
} else {
array.add(temp.getNext());
temp=temp.getNext();
}
}
//使用collections.sort排序,使用lambda表达式重写Comparator比较器,根据num排序升序
Collections.sort(array,(Node t,Node t1)->{return t.getNum()-t1.getNum();});
//stream流forEach遍历array
array.stream().forEach(i-> System.out.println(i));
}
}
}
public class DemoNode {
public static void main(String[] args) {
Node one = new Node(1, "宋江", "及时雨");
Node two = new Node(2, "卢俊义", "玉麒麟");
Node three = new Node(3, "吴用", "智多星");
Node four = new Node(4, "公孙胜", "入云龙");
Node five = new Node(5, "关胜", "大刀");
/* SingeLinkedList singeLinkedList = new SingeLinkedList();
singeLinkedList.add(four);
singeLinkedList.add(five);
singeLinkedList.add(one);
singeLinkedList.add(three);
singeLinkedList.add(two);
singeLinkedList.list();*/
SingeLinkedList02 singeLinkedList02 = new SingeLinkedList02();
singeLinkedList02.add(five);
singeLinkedList02.add(one);
singeLinkedList02.add(three);
singeLinkedList02.add(two);
singeLinkedList02.add(four);
singeLinkedList02.list();
}
}
教程方法:
1.首先找到新添加的节点的位置, 是通过辅助变量temp(指针), 通过遍历来搞定
2.新的节点.next = temp.next
3.将temp.next = 新的节点
public class SingeLinkedList {
//先创建一个head 头节点, 作用就是表示单链表的头
private Node firstNode = new Node(0, "", "");
//后面我们每添加一个节点,就直接加入到 链表的最后
//思路 当不考虑编号的顺序的时候
//1.找到当前链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(Node node) {
//1.找到最后一个节点,每次查询元素都要从头开始
Node temp = firstNode;
while (true) {
if (temp.getNext() == null) {
break;
} else {
temp = temp.getNext();
}
}
//2.将最后这个节点的next指向新的节点
temp.setNext(node);
}
//添加考虑编号的顺序
//如果存在相同顺序,则添加失败,并显示已存在
public void addByOrder(Node node) {
Node temp = firstNode;
boolean flag = false;//标识插入node的序号是否已经存在
//使用循环,寻找node节点的前一个节点
while (true) {
if (temp.getNext()==null){
break;//如果首节点的下一个节点为空,首节点就是node前一个节点,找到node的前一个节点
}else if (temp.getNext().getNum()>node.getNum()){//如果temp的下一个节点的编号大于node的编号,说明node应该插入temp和temp的下一个节点之间
break;//找到node的前一个节点
}else if (temp.getNext().getNum()==node.getNum()){//如果temp的下一个节点的编号等于node的编号,说明节点重复
flag=true;
break;
}
temp=temp.getNext();//循环
}
//node应该插入链表
//如果存在相同顺序,则添加失败,并显示已存在
if (flag==true){
System.out.println("编号为"+node.getNum()+"的节点已经存在");
}else {
node.setNext(temp.getNext());//将node节点插到temp后一个节点之前
temp.setNext(node);//将节点插到temp节点之后
}
}
//通过一个辅助变量遍历,帮助遍历整个链表
public void list() {
//先判断链表是否为空
if (firstNode.getNext() == null) {
System.out.println("链表为空");
} else {
//因为头节点不能动 因此需要一个辅助变量
Node temp = firstNode;
while (true) {
//判断链表是否到最后
if (temp.getNext() == null) {
break;
} else {
//输出节点的信息
System.out.println(temp.getNext());
//将 temp 后移
temp = temp.getNext();
}
}
}
}
}
public class DemoNode {
public static void main(String[] args) {
Node one = new Node(1, "宋江", "及时雨");
Node two = new Node(2, "卢俊义", "玉麒麟");
Node three = new Node(3, "吴用", "智多星");
Node four = new Node(4, "公孙胜", "入云龙");
Node five = new Node(5, "关胜", "大刀");
SingeLinkedList singeLinkedList = new SingeLinkedList();
singeLinkedList.addByOrder(four);
singeLinkedList.addByOrder(five);
singeLinkedList.addByOrder(one);
singeLinkedList.addByOrder(three);
singeLinkedList.addByOrder(two);
singeLinkedList.addByOrder(two);
singeLinkedList.list();
/* SingeLinkedList02 singeLinkedList02 = new SingeLinkedList02();
singeLinkedList02.add(five);
singeLinkedList02.add(one);
singeLinkedList02.add(three);
singeLinkedList02.add(two);
singeLinkedList02.add(four);
singeLinkedList02.list();*/
}
}
2.节点信息的修改
根据node编号,修改node里面的信息
public class SingeLinkedList {
//先创建一个head 头节点, 作用就是表示单链表的头
private Node firstNode = new Node(0, "", "");
/*链表添加节点法一:每添加一个节点,就直接加入到 链表的最后*/
//后面我们每添加一个节点,就直接加入到 链表的最后
//思路 当不考虑编号的顺序的时候
//1.找到当前链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(Node node) {
//1.找到最后一个节点,每次查询元素都要从头开始
Node temp = firstNode;
while (true) {
if (temp.getNext() == null) {
break;
} else {
temp = temp.getNext();
}
}
//2.将最后这个节点的next指向新的节点
temp.setNext(node);
}
/*链表添加节点法二:每添加一个节点,添加考虑编号的顺序*/
//添加考虑编号的顺序
//如果存在相同顺序,则添加失败,并显示已存在
public void addByOrder(Node node) {
Node temp = firstNode;
boolean flag = false;//标识插入node的序号是否已经存在
//使用循环,寻找node节点的前一个节点
while (true) {
if (temp.getNext()==null){
break;//如果首节点的下一个节点为空,首节点就是node前一个节点,找到node的前一个节点
}else if (temp.getNext().getNum()>node.getNum()){//如果temp的下一个节点的编号大于node的编号,说明node应该插入temp和temp的下一个节点之间
break;//找到node的前一个节点
}else if (temp.getNext().getNum()==node.getNum()){//如果temp的下一个节点的编号等于node的编号,说明节点重复
flag=true;
break;
}
temp=temp.getNext();//循环
}
//node应该插入链表
//如果存在相同顺序,则添加失败,并显示已存在
if (flag==true){
System.out.println("编号为"+node.getNum()+"的节点已经存在");
}else {
node.setNext(temp.getNext());//将node节点插到temp后一个节点之前
temp.setNext(node);//将节点插到temp节点之后
}
}
/*遍历整个链表*/
//通过一个辅助变量遍历,帮助遍历整个链表
public void list() {
//先判断链表是否为空
if (firstNode.getNext() == null) {
System.out.println("链表为空");
} else {
//因为头节点不能动 因此需要一个辅助变量
Node temp = firstNode;
while (true) {
//判断链表是否到最后
if (temp.getNext() == null) {
break;
} else {
//输出节点的信息
System.out.println(temp.getNext());
//将 temp 后移
temp = temp.getNext();
}
}
}
}
/*修改节点信息*/
public void updata(Node node){
if (firstNode.getNext()==null){//如果头结点的下一个节点为null,则链表为空
System.out.println("链表为空");
}else{
Node temp = firstNode;//若不为空,开始遍历链表,寻找num
while (true){
if (temp.getNum()==node.getNum()){//找到编号,修改数据
temp.setName(node.getName());
temp.setNickname(node.getNickname());
break;
}else if (temp.getNext()==null){//找不到编号,打印信息
System.out.println("不存在编号为"+node.getNum()+"的节点");
break;
}else {//temp指针循环
temp=temp.getNext();
}
}
}
}
}
public class Demo02 {
public static void main(String[] args) {
Node one = new Node(1, "宋江", "及时雨");
Node two = new Node(2, "卢俊义", "玉麒麟");
Node three = new Node(3, "吴用", "智多星");
Node four = new Node(4, "公孙胜", "入云龙");
Node five = new Node(5, "关胜", "大刀");
SingeLinkedList singeLinkedList = new SingeLinkedList();
singeLinkedList.addByOrder(four);
singeLinkedList.addByOrder(five);
singeLinkedList.addByOrder(one);
singeLinkedList.addByOrder(three);
singeLinkedList.addByOrder(two);
singeLinkedList.list();
Node newNode = new Node(2,"更改name","更改nickname");
singeLinkedList.updata(newNode);
System.out.println("更新如下:");
singeLinkedList.list();
Node newNode2 = new Node(12,"更改name","更改nickname");
singeLinkedList.updata(newNode2);
System.out.println("更新如下:");
singeLinkedList.list();
}
}
3.删除节点
public class SingeLinkedList {
//先创建一个head 头节点, 作用就是表示单链表的头
private Node firstNode = new Node(0, "", "");
/*链表添加节点法一:每添加一个节点,就直接加入到 链表的最后*/
//后面我们每添加一个节点,就直接加入到 链表的最后
//思路 当不考虑编号的顺序的时候
//1.找到当前链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(Node node) {
//1.找到最后一个节点,每次查询元素都要从头开始
Node temp = firstNode;
while (true) {
if (temp.getNext() == null) {
break;
} else {
temp = temp.getNext();
}
}
//2.将最后这个节点的next指向新的节点
temp.setNext(node);
}
/*链表添加节点法二:每添加一个节点,添加考虑编号的顺序*/
//添加考虑编号的顺序
//如果存在相同顺序,则添加失败,并显示已存在
public void addByOrder(Node node) {
Node temp = firstNode;
boolean flag = false;//标识插入node的序号是否已经存在
//使用循环,寻找node节点的前一个节点
while (true) {
if (temp.getNext() == null) {
break;//如果首节点的下一个节点为空,首节点就是node前一个节点,找到node的前一个节点
} else if (temp.getNext().getNum() > node.getNum()) {//如果temp的下一个节点的编号大于node的编号,说明node应该插入temp和temp的下一个节点之间
break;//找到node的前一个节点
} else if (temp.getNext().getNum() == node.getNum()) {//如果temp的下一个节点的编号等于node的编号,说明节点重复
flag = true;
break;
}
temp = temp.getNext();//循环
}
//node应该插入链表
//如果存在相同顺序,则添加失败,并显示已存在
if (flag == true) {
System.out.println("编号为" + node.getNum() + "的节点已经存在");
} else {
node.setNext(temp.getNext());//将node节点插到temp后一个节点之前
temp.setNext(node);//将节点插到temp节点之后
}
}
/*遍历整个链表*/
//通过一个辅助变量遍历,帮助遍历整个链表
public void list() {
//先判断链表是否为空
if (firstNode.getNext() == null) {
System.out.println("链表为空");
} else {
//因为头节点不能动 因此需要一个辅助变量
Node temp = firstNode;
while (true) {
//判断链表是否到最后
if (temp.getNext() == null) {
break;
} else {
//输出节点的信息
System.out.println(temp.getNext());
//将 temp 后移
temp = temp.getNext();
}
}
}
}
/*修改节点信息*/
public void updata(Node node) {
if (firstNode.getNext() == null) {//如果头结点的下一个节点为null,则链表为空
System.out.println("链表为空");
} else {
Node temp = firstNode;//若不为空,开始遍历链表,寻找num
while (true) {
if (temp.getNum() == node.getNum()) {//找到编号,修改数据
temp.setName(node.getName());
temp.setNickname(node.getNickname());
break;
} else if (temp.getNext() == null) {//找不到编号,打印信息
System.out.println("不存在编号为" + node.getNum() + "的节点");
break;
} else {//temp指针循环
temp = temp.getNext();
}
}
}
}
/*根据节点编号,删除节点*/
public void deletNode(int n) {
if (firstNode.getNext() == null) {
System.out.println("链表为空");
} else {
Node temp = firstNode;
while (true) {
if (temp.getNext().getNum() == n) {//如果temp的下一个节点num为n,找到要删的节点
temp.setNext(temp.getNext().getNext());//将temp的下一个节点链接到下下个节点
break;
} else if (temp.getNext() == null) {
System.out.println("链表中没有" + n + "节点");
break;
} else {
temp = temp.getNext();
}
}
}
}
}