单链表结构的创建及实现单链表的增删改查:
//定义一个LinkedList来管理我们的英雄
class LinkedList{
//初始化头节点,头节点不能动
private HeroNode head = new HeroNode(0,"","");
//返回头节点
public HeroNode getHead(){
return head;
}
//添加英雄的方法(不考虑排名)
public void addNode(HeroNode heroNode){
//定义一个临时节点,用于遍历链表
HeroNode temp = head;
//当temp.next=null时可以把节点添加到链表中
while (true){
if (temp.next==null){
break;
}
//如果temp.next不为空,则temp后移
temp = temp.next;
}
//退出循环时进行添加节点,加在temp后面
temp.next = heroNode;
}
//遍历链表的方法,用于查看排行
public void showLinkedList(){
//判断链表是否为空
if (head.next==null){
System.out.println("链表为空");
}
//定义一个临时节点,用于遍历链表
HeroNode temp = head.next;
while (true){
if (temp==null){
break;
}
System.out.println(temp);
//每次输出完信息后,指针后移
temp = temp.next;
}
}
//第二种方式在添加英雄时,根据排名将英雄插入到指定位置
//(如果有这个排名,则添加失败,并给出提示)
public void addByOrder(HeroNode heroNode){
//定义一个临时变量,用于遍历链表
HeroNode temp = head;
boolean flag = false;
while (true){
if (temp.next==null){
//链表为空,直接插入
break;
}
if (temp.next.no>heroNode.no){
//要插入的节点的排名位于temp和temp.next之间,可以插入
break;
}else if (temp.next.no == heroNode.no){
//要插入的节点以及存在,不可以插入
flag = true;
}
//temp后移
temp = temp.next;
}
if (flag){
System.out.println("要插入的节点已存在,不能进行添加");
}else{
//插入到temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//删除节点的方法
public void delNode(int no){
//定义一个临时节点,用于遍历链表
HeroNode temp = head;
boolean flag = false;
while (true){
if (temp.next==null){
//链表为空
break;
}
if (temp.next.no ==no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag){
//找到则进行删除
//遍历节点的下一个节点是要删除的节点,把临时节点,赋值给删除的节点的下一个节点,则要删除的节点会被gc回收
temp.next = temp.next.next;
}else {
System.out.printf("要删除的%d节点不存在\n",no);
}
}
//修改节点信息
public void upgradeNode(HeroNode newNode){
if (head.next==null){
System.out.println("链表为空~");
return;
}
//定义一个临时节点
//通过no来修改
HeroNode temp = head;
boolean flag = false;//标志是否找到该节点
while (true){
if (temp.next == null){
break;
}
if(temp.next.no==newNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
//进行修改
temp.next.name = newNode.name;
temp.next.nickName = newNode.nickName;
}else {
System.out.println("没有找到该节点");
}
}
}
//英雄节点,每个节点中存放数据域data和指向的下一个节点next指针
class HeroNode{
public int no;//英雄排名
public String name;//英雄名字
public String nickName;//英雄绰号
public HeroNode next;//指向下一个节点
public HeroNode(int hNo,String hName,String hNickname){
this.no = hNo;
this.name = hName;
this.nickName = hNickname;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' + '}';
}
}
单链表的练习题:
package com.xatu.linkedlist;
import org.junit.Test;
import java.util.Stack;
/**
* @author blackCat
* @create 2022-07-28 22:26
*/
public class SingleLinkedListExer {
/*
求单链表中有效节点的个数
*/
@Test
public void test1(){
HeroNode node1 = new HeroNode(1,"宋江","及时雨");
HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode node3 = new HeroNode(3,"林冲","豹子头");
HeroNode node4 = new HeroNode(4,"关胜","大刀");
LinkedList list = new LinkedList();
list.addNode(node1);
list.addNode(node2);
list.addNode(node3);
list.addNode(node4);
list.showLinkedList();
int length = getLength(list.getHead());
System.out.println("有效节点的个数为:"+length);
}
//不计算头节点
public static int getLength(HeroNode head) {
if (head.next==null){
return 0;
}
//定义一个临时变量用于遍历链表
HeroNode temp = head.next;
int length = 0;
while (temp!=null){
length++;
temp = temp.next;
}
return length;
}
/*
查找单链表中的倒数第k个节点
*/
@Test
public void test2(){
HeroNode node1 = new HeroNode(1,"宋江","及时雨");
HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode node3 = new HeroNode(3,"林冲","豹子头");
HeroNode node4 = new HeroNode(4,"关胜","大刀");
LinkedList list = new LinkedList();
list.addNode(node1);
list.addNode(node2);
list.addNode(node3);
list.addNode(node4);
//list.showLinkedList();
HeroNode lastIndexNode = findLastIndexNode(list.getHead(), 3);
System.out.println("单链表倒数第k个节点为:"+lastIndexNode);
}
public HeroNode findLastIndexNode(HeroNode head,int index){
if (head.next==null){
//链表为空,返回null
return null;
}
//获取链表的有效个数
int size = getLength(head);
//校验index的有效性
if (index<0||index>size){
return null;
}
//遍历链表,遍历(size-index)次
//定义一个临时节点,用于遍历
HeroNode temp = head.next;
for (int i = 0; i < (size - index); i++) {
temp = temp.next;
}
return temp;
}
/*
单链表的反转
*/
@Test
public void test3(){
HeroNode node1 = new HeroNode(1,"宋江","及时雨");
HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode node3 = new HeroNode(3,"林冲","豹子头");
HeroNode node4 = new HeroNode(4,"关胜","大刀");
LinkedList list = new LinkedList();
list.addNode(node1);
list.addNode(node2);
list.addNode(node3);
list.addNode(node4);
reverseList(list.getHead());
System.out.println("反转后的单链表为:");
list.showLinkedList();
}
//思路:1.先定义一个节点reverseHead
//2.遍历初始链表,每遍历一个节点,就将其取出,并放在新链表的头节点reverseHead的最前端
public void reverseList(HeroNode head){
//如果链表为空,或链表只有一个元素则无需反转
if (head.next==null||head.next.next==null){
return;
}
//定义一个reverseHead
HeroNode reverseHead = new HeroNode(0,"","");
//定义一个临时节点,用于遍历
HeroNode temp = head.next;
//定义一个节点,用于保存[temp]后一个节点
HeroNode next = null;
while (temp!=null){
next = temp.next;
temp.next = reverseHead.next;//保证reverseHead每次都连接的是temp的后面的节点
reverseHead.next = temp;
temp = next;//把temp连接到新链表上
}
head.next = reverseHead.next;//原始链表的同节点取代新链表的头节点,实现反转
}
/*
从头到尾打印单链表(使用栈存取节点、利用栈先进后出的特点)
*/
@Test
public void test4(){
HeroNode node1 = new HeroNode(1,"宋江","及时雨");
HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode node3 = new HeroNode(3,"林冲","豹子头");
HeroNode node4 = new HeroNode(4,"关胜","大刀");
LinkedList list = new LinkedList();
list.addNode(node1);
list.addNode(node2);
list.addNode(node3);
list.addNode(node4);
System.out.println("从头到尾打印单链表:");
reversePrint(list.getHead());
}
public void reversePrint(HeroNode head){
if (head.next==null){
return;//空链表
}
Stack<HeroNode> stack = new Stack<>();
HeroNode temp = head.next;
while (temp!=null){
stack.push(temp);//把数据压入栈
temp = temp.next;//指针后移
}
//遍历栈中的数据
while (stack.size()>0){
System.out.println(stack.pop());
}
}
//将两个有序单链表合并成一个有序单链表
@Test
public void test(){
HeroNode node1 = new HeroNode(3,"宋江","及时雨");
HeroNode node2 = new HeroNode(5,"卢俊义","玉麒麟");
HeroNode node3 = new HeroNode(9,"林冲","豹子头");
HeroNode node4 = new HeroNode(7,"关胜","大刀");
LinkedList list1 = new LinkedList();
list1.addByOrder(node1);
list1.addByOrder(node2);
list1.addByOrder(node3);
list1.addByOrder(node4);
HeroNode node5 = new HeroNode(1,"张无忌","大魔头");
HeroNode node6 = new HeroNode(6,"张三丰","大大魔头");
HeroNode node7 = new HeroNode(2,"谢逊","小魔头");
HeroNode node8 = new HeroNode(4,"周芷若","小小魔头");
HeroNode node9 = new HeroNode(8,"张翠山","小小小魔头");
LinkedList list2 = new LinkedList();
list2.addByOrder(node5);
list2.addByOrder(node6);
list2.addByOrder(node7);
list2.addByOrder(node8);
list2.addByOrder(node9);
System.out.println("合并前的两个有序列表");
list1.showLinkedList();
System.out.println();
list2.showLinkedList();
LinkedList list3 = mergeList(list1, list2);
System.out.println("两个有序列表合并后的有序列表");
list3.showLinkedList();
}
public LinkedList mergeList(LinkedList list1,LinkedList list2){
//思路
//初始化n1,n2两个指针,n1指向list1的第一个节点,n2指向list2的第一个节点
//初始化n3,指向list1的头节点
//当n1,n2没有到达单链表的尾部时,选出排名较小的节点赋值给n3.next
//当n1或n2到达链表尾部时,n3指向后到达尾部的节点
HeroNode n1 = list1.getHead().next;
HeroNode n2 = list2.getHead().next;
HeroNode n3 = list1.getHead();
while (n1!=null&&n2!=null){
if (n1.no>=n2.no){
n3.next = n2;
n2 = n2.next;
}else {
n3.next = n1;
n1 = n1.next;
}
n3 = n3.next;
}
n3.next = n1 == null ?n1:n2;
return list1;
}
}