package com.hao.firstdemo.datastruct;
import java.util.Stack;
/**
* @author haoxiansheng
*/
public class TestSingleLinkedList {
public static void main(String[] args) {
//测试 你就可以在这里玩链表了 哈哈
HeroNode node1 = new HeroNode(1, "曹操", "奸雄");
HeroNode node2 = new HeroNode(2, "刘备", "小人");
HeroNode node3 = new HeroNode(3, "赵云", "忠义之士");
HeroNode node4 = new HeroNode(4, "关羽", "关二爷");
SingleLinkedList linkedList = new SingleLinkedList();
linkedList.add(node1);
linkedList.add(node2);
linkedList.add(node3);
linkedList.add(node4);
linkedList.show();
HeroNode node5 = new HeroNode(4, "关平", "关二爷");
linkedList.update(node5);
linkedList.show();
//测试
System.out.println("有效的头节点为" + getLength(linkedList.getHead()));
}
/**
* 返回链表的有效个数 没有统计头节点
*
* @param heroNode 链表的头节点
* @return
*/
public static int getLength(HeroNode heroNode) {
int len = 0;
if (heroNode.next == null) {
//空链表
return len;
}
//借助辅助变量
HeroNode current = heroNode.next;
while (current != null) {
len++;
current = current.next;
}
return len;
}
/**
* 思路
* 1、编写一个接收 节点和 index 参数(标识倒数第几个)
* 2、先得到链表的大小size,然后遍历size-index次就好
* 3、找到返回 没有返回null
*
* @param head 头节点
* @param index 倒数第几个数
* @return 求指定倒数个数的节点
*/
public static HeroNode getLastIndexNode(HeroNode head, int index) {
if (head == null) {
return null; //没有找到返回null
}
int size = getLength(head);
if (index <= 0 || index > size) {
return null;
}
//定义辅助变量
HeroNode temp = head.next;
for (int i = 0; i < size - index; i++) {
temp = temp.next;
}
return temp;
}
/**
* 将单链表反转
* 头节点 => 1 => 2 => 5 => 9 反转 头节点 => 9 => 5 => 2 => 1
* 1、先定义一个节点reverseHead = new HeroNode();
* 2、从头到尾遍历原来的链表,每遍历一个,将其取出,并放在reverseHead的最前面;
* 3、原来的链表的head.next=reverseHead.next
* 这道题有点绕需要研究懂while种的几行代码
*/
public static void reverseList(HeroNode head) {
if (head.next == null || head.next.next == null) {
return;
}
HeroNode current = head.next; //辅助遍历
HeroNode next = null; //指向当前节点[current]的下一个节点
HeroNode reverseHead = new HeroNode(0, "", "");
//遍历原来的链表,每遍历一个就将其取出并放在链表reverseHead的下一个节点的最前端
while (current != null) {
next = current.next; //先暂时保存当前节点的下一个节点,因为后续要使用
current.next = reverseHead.next; //将current的下一个节点指向新链表的最前端(也就是reverseHead 后面)
reverseHead.next = current; //将current连接到最新的链表上
current = next; //让current 后移
}
//将head.next 指向reverseHead.next, 实现链表的反转
head.next = reverseHead.next;
}
/**
* 从未到头打印单链表
* 思路:用栈的方式
*/
public static void reversePrint(HeroNode head) {
if (head.next == null) {
return;
}
//创建一个栈 将node压入栈中
Stack<HeroNode> heroNodeStack = new Stack<>();
HeroNode temp = head.next;
while (temp != null) {
heroNodeStack.add(temp);
temp = temp.next;
}
while (heroNodeStack.size() > 0) {
System.out.println(heroNodeStack.pop());
}
}
}
//定义一个类管理列表
class SingleLinkedList {
//先初始化一个头节点,头节点不要动 不存放具体数据 后续遍历查找需要使用头节点
private HeroNode head = new HeroNode(0, "", "");
public HeroNode getHead() {
return head;
}
/**
* 添加节点到单向链表
* 思路一:不考虑编号 1、找到当前链表的最后节点 2、将最后这个节点的next 指向新的节点
*/
public void add(HeroNode heroNode) {
//head节点不能动, 因此我们需要一个辅助遍历temp
HeroNode temp = head;
//循环遍历 找到最后 temp.next == null
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
//将最后这个节点 next 指向新的节点
temp.next = heroNode;
}
/**
* 第二种思路
* 添加时是有顺序的 然后根据这个number 大小
* 如果有这个排名 添加失败并给出提示
*/
public void addByOrder(HeroNode heroNode) {
// 辅助遍历帮找添加的位置 因为是单链表 我们找的temp 是位于添加位置的前一个位置 否则添加不了
HeroNode temp = head;
boolean flag = false; //标识添加的编号是否存在 默认不存在
while (true) {
if (temp.next == null) { //已经在链表最后
break;
}
if (temp.next.number > heroNode.number) { //位置找到,就在temp后面插入
break;
}
if (temp.next.number == heroNode.number) { //说明添加的节点已经存在
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.printf("准备添加的数据%d 已经存在了", heroNode.number);
} else {
// 插入到链表中 这点有点绕 类似于 A C B 变量赋值
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 显示链表
*/
public void show() {
if (head.next == null) {
System.out.println("链表为null");
}
HeroNode temp = head.next;
while (true) {
if (temp == null) {
System.out.println("链表为空");
return;
}
//打印信息、节点后移
System.out.println(temp);
temp = temp.next;
}
}
/**
* 修改节点 根据number 来修改 number的编号不能变化
*/
public void update(HeroNode newHeroNode) {
//判断队列是否为null
if (head.next == null) {
System.out.println("队列为null");
return;
}
//找到需要修改的节点 定义辅助变量
HeroNode temp = head.next;
boolean flag = false;
while (true) {
if (temp == null) {
System.out.println("队列为null");
break;
}
if (temp.number == newHeroNode.number) {
flag = true;
break;
}
temp = temp.next;
}
//判断
if (flag) {
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
} else {
System.out.printf("没有找到%d的节点", newHeroNode.number);
}
}
/**
* 删除节点
* 思路:1、head 不能动 需要一个辅助节点temp 找到删除节点的前一个节点
* 2、temp.next.number 和要删除的进行比较
*/
public void del(int number) {
HeroNode temp = head;
boolean flag = false; //标识是否找到代删除的节点。
while (true) {
if (temp.next == null) { //已经到链表的最后
break;
}
if (temp.next.number == number) { //找到带删除节点的前一个节点
flag = true;
break;
}
temp = temp.next;
}
//判断是否找到 找到删除
if (flag) {
temp.next = temp.next.next;
} else {
System.out.println("没有找到待删除的节点");
}
}
}
//定义一个节点 每个HeroNode 对象就是一个节点
class HeroNode {
public int number;
public String name; //名字
public String nickName; //昵称
public HeroNode next; // 指向下一个域
/**
* 构造器
*
* @param number
* @param name
* @param nickName
*/
public HeroNode(int number, String name, String nickName) {
this.number = number;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"number=" + number +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}