完整代码如下:
package com.wqc.linkedlist;
import java.util.Stack;
/**
* @author 高瞻远瞩
* @version 1.0
* @motto 算法并不可怕, 可怕的是你不敢面对它, 加油!冲击大厂!!!
* 演示单链表的使用
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
SingleLinkedList singleLinkedList = new SingleLinkedList();
// singleLinkedList.addSingleLinkedList(new Node(1, "宋江", "及时雨"));
// singleLinkedList.addSingleLinkedList(new Node(4, "公孙胜", "道号一清"));
// singleLinkedList.addSingleLinkedList(new Node(3, "吴用", "智多星"));
// singleLinkedList.addSingleLinkedList(new Node(2, "卢俊义", "玉麒麟"));
//按照编号的顺序添加
singleLinkedList.addByOrder(new Node(1, "宋江", "及时雨"));
singleLinkedList.addByOrder(new Node(3, "公孙胜", "道号一清"));
singleLinkedList.addByOrder(new Node(6, "华容", "小李广"));
singleLinkedList.addByOrder(new Node(8, "卢俊义", "玉麒麟"));
singleLinkedList.addByOrder(new Node(10, "武松", "断臂"));
singleLinkedList.showSingleLinkedList();
System.out.println("====修改之后链表====");
singleLinkedList.update(new Node(1, "小宋", "及时雨"));//修改
singleLinkedList.showSingleLinkedList();
// //删除操作
// System.out.println("====删除之后链表====");
// singleLinkedList.delete(5);
// singleLinkedList.delete(1);
// singleLinkedList.showSingleLinkedList();
// System.out.println("单链表有效结点的个数=" + getLength(singleLinkedList.head));
// System.out.println("倒数第2个结点 " + find(singleLinkedList.head, 2));
// //反转
// reverse(singleLinkedList.head);
// System.out.println("==========反转过后===========");
// singleLinkedList.showSingleLinkedList();
// //倒叙打印
// System.out.println("==========倒叙打印===========");
// flashBackPrint(singleLinkedList.head);
// System.out.println("=========");
// SingleLinkedList singleLinkedList2 = new SingleLinkedList();
// singleLinkedList2.addByOrder(new Node(2, "吴用", "智多星"));
// singleLinkedList2.addByOrder(new Node(4, "李逵", "黑旋风"));
// singleLinkedList2.addByOrder(new Node(5, "鲁智深", "和尚"));
// singleLinkedList2.addByOrder(new Node(7, "林冲", "豹子头"));
// singleLinkedList2.showSingleLinkedList();
// System.out.println("=========合并后===========");
// merge(singleLinkedList.head, singleLinkedList2.head);
}
//将两个有序的单链表合并成一个有序的单链表
//思路是 两两比较 选出较小的加入到新定义的头结点之后 然后删除在原来链表的连线
//最后把不为null的那个链表和新定义的那个链表连接即可
public static void merge(Node head1, Node head2) {
Node newNode = new Node(0, "", "");
Node temp = newNode;
while (head1.next != null && head2.next != null) {
if (head1.next.id < head2.next.id) {
temp.next = head1.next;//新结点指向两个链表的第一个结点比较后id小的结点
head1.next = head1.next.next;//把这个id较小的结点从原来的链表删除
} else {
temp.next = head2.next;
head2.next = head2.next.next;
}
temp = temp.next;//temp后移
}
//然后都比较过后 判断哪个链表不为null 不为null的链表的最小值一定大于新链表的最大值
if (head1.next != null) {
temp.next = head1.next;//将新链表的最后一个结点的next域指向不为空的那个链表的第一个结点
head1.next = null;
}
if (head2.next != null) {
temp.next = head2.next;
head2.next = null;
}
while (newNode.next != null) {
newNode = newNode.next;
System.out.println(newNode);
}
}
//从尾到头打印单链表 ----> 引出栈 先进后出
public static void flashBackPrint(Node head) {
Stack<Node> stack = new Stack<>();
if (head.next == null) {//如果单链表为空直接返回
return;
}
if (head.next.next == null) {//如果长度为1 直接打印
System.out.println(head.next);
return;
}
while (head.next != null) {
head = head.next;
stack.push(head);//遍历 将单链表的结点依次入栈
}
while (stack.size() > 0) {
System.out.println(stack.pop());//弹栈
}
}
//查找单链表中的倒数第k个结点
public static Node find(Node head, int index) {
if (head.next == null) {//如果链表为null
return null;
}
Node temp = head.next;
int length = getLength(head);
if (index <= 0 || index > length) {
return null;//对index下标进行验证
}
//用for循环再次遍历到length-index 从0开始遍历
//假设链表一共有5个有效的结点 要找倒数第一个结点 从0遍历到3 temp一共移动4次
for (int i = 0; i < length - index; i++) {
temp = temp.next;
}
return temp;
}
//获取到单链表有效结点的个数 头结点不算
public static int getLength(Node head) {
if (head.next == null) {//如果链表为null 返回0
return 0;
}
int nodeNums = 0;
while (head.next != null) {
nodeNums++;
head = head.next;
}
return nodeNums;
}
//单链表的反转
public static void reverse(Node head) {
if (head.next == null || head.next.next == null) {
return;
}
Node cur = head.next;
Node next = null;
Node newHead = new Node(0, "", "");//定义一个新的头结点
while (cur != null) {
next = cur.next;
cur.next = newHead.next;//让现在指向的结点指向新的头结点的下一个结点
newHead.next = cur;//新的头结点的下一个结点指向现在的结点
cur = next;
}
head.next = newHead.next;
}
}
//定义一个单链表
class SingleLinkedList {
//先定义一个头节点 next域为null 作为成员变量
Node head = new Node(0, "", "");
//删除单链表的结点信息
public void delete(int id) {
//判断链表是否为null
if (head.next == null) {
System.out.println("链表为null。。。");
return;
}
Node temp = head;
boolean loop = false;
//先循环遍历 找到要删除的结点的前一个结点 用temp保存
while (true) {
if (temp.next == null) {//遍历结束
break;
}
if (temp.next.id == id) {
loop = true;
break;
}
temp = temp.next;
}
if (loop) {//找到了
temp.next = temp.next.next;
} else {
System.out.println("没有找到该结点...");
}
}
//修改单链表结点的信息 默认认为id号是判断标准
public void update(Node newNode) {
Node temp = head.next;
//先判断链表是否null
if (temp == null) {
System.out.println("链表为null");
return;
}
boolean flag = false;//定义是否找到的标志
//找到要修改信息的Node结点
while (true) {
//需要先考虑遍历结束的情况 因为如果不这样 先判断id是否相等的话 遍历结束时 temp的next域为null 所以temp.id会报空指针异常
if (temp == null) {
break;
}
if (temp.id == newNode.id) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.name = newNode.name;
temp.nickname = newNode.nickname;
} else {
System.out.printf("没有找到编号%d的结点\n", newNode.id);
}
}
//添加元素到单链表 尾插法
public void addSingleLinkedList(Node node) {
//先定义一个临时的结点 让他指向头节点 方便遍历
Node temp = head;
/**
* head.next是Node结点里面的一个对象引用(成员属性) temp也是一个对象引用
* 两者不能混为一谈 单链表的指向是Node结点里面的一个对象引用的指向
*/
while (true) { //插入的思路是--》先找到最后一个结点 然后插入
if (temp.next == null) {
break;
}
//然后让temp结点的指向后移
temp = temp.next;
}
//while循环的退出条件就是temp结点指向了最后一个结点
temp.next = node;//让temp的next域 即next的Node对象引用指向传进来的node结点
}
//按照编号的顺序插入Node结点 思路:先找到插入结点的位置 因为这里只有next域 所以要找到插入结点位置的前面的那个结点
public void addByOrder(Node node) {
//定义一个临时的结点 指向头接待你 方便遍历
Node temp = head;
boolean flag = false;//flag为控制是否为重复元素
while (true) {
if (temp.next == null) {//这种情况说明单链表为null 直接到头节点的后面插入即可 同时也是遍历结束的条件
// 同时也是遍历到最后一个结点 只能插入到最后一个结点的情况
break;
}
if (temp.next.id > node.id) { //这种情况说明temp结点即为要找的那个位置 1,temp 2,node 3,temp.next
break;
}
if (temp.next.id == node.id) {//如果插入结点的id已经存在 则应提示不能插入
flag = true;
break;
}
//如果以上条件都不符合 就让temp结点后移继续寻找
temp = temp.next;
}
if (flag) {
System.out.printf("%d结点已存在\n", node.id);
} else {
node.next = temp.next;
temp.next = node;
}
}
//显示单链表的所有结点信息
public void showSingleLinkedList() {
if(head.next == null){
System.out.println("链表为null,显示失败...");
}
//定义一个临时结点 方便遍历
Node temp = head;
// while (true) {
// //先判断next域是否为null 如果为null 直接跳出
// if (temp.next == null) {
// break;
// }
// temp = temp.next;//指向单链表的下一个结点
// System.out.println(temp);//打印结点信息 默认调用toString方法
// }
while (temp.next != null) {//另一种遍历方式
temp = temp.next;
System.out.println(temp);
}
}
}
//先定义一个结点类 每一个结点代表一个对象
class Node {
int id;
String name;//名字
String nickname;//昵称
Node next;//next域 作为一个对象引用 指向下一个结点
public Node(int id, String name, String nickname) {
this.id = id;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "Node{" +
"id=" + id +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}