链表
单链表创建和遍历代码实现
package dataStructure.LinkedList;
/**
* @author
* @date 2024-04-12 14:52
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1,"宋江1","及时雨1");
HeroNode hero2 = new HeroNode(1,"宋江2","及时雨2");
HeroNode hero3 = new HeroNode(1,"宋江3","及时雨3");
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.list();
}
}
class SingleLinkedList {
//初始化头节点,头节点不存放数据
private HeroNode head = new HeroNode(0,"","");
//添加节点到单向链表
//1.找到当前链表的最后一个节点
//2.将最后这个节点的next指向新的节点
public void add(HeroNode heroNode) {
//因为head节点不能动,因此我们需要一个辅助遍历temp
HeroNode temp = head;
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
//当退出while循环时,temp就指向了链表的最后
//将最后这个节点的next指向新的节点
temp.next = heroNode;
}
//显示链表
public void list() {
if (head.next == null) {
System.out.println("链表为空");
return;
}
//因为头节点不能动,需要辅助变量
HeroNode temp = head.next;
while (true) {
//判断是否到链表最后
if (temp == null ){
break;
}
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
}
//定义HeroNode,每个HeroNode对象都是一个节点
class HeroNode {
public int no;
public String name;
public String nickname;
public HeroNode next; //指向下一个节点
public HeroNode(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
单链表代码实现(按编号顺序添加)
public void addByOrder(HeroNode heroNode) {
//因为单链表,temp是位于添加位置的前一个节点
HeroNode temp = head;
boolean flag = false; //flag标志添加的编号是否存在,默认为false
while (true) {
if (temp.next == null ){
//已经到链表的最后
break;
}
if (temp.next.no > heroNode.no) {
//在temp的d当前位置添加
break;
} else if (temp.next.no == heroNode.no) {
//编号已存在
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.printf("准备插入的英雄编号 %d 已经存在",heroNode.no);
} else {
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//测试在psvm中
HeroNode hero4 = new HeroNode(4,"宋江4","及时雨4");
HeroNode hero5 = new HeroNode(5,"宋江5","及时雨5");
HeroNode hero6 = new HeroNode(6,"宋江6","及时雨6");
SingleLinkedList singleLinkedList1 = new SingleLinkedList();
singleLinkedList1.addByOrder(hero4);
singleLinkedList1.addByOrder(hero6);
singleLinkedList1.addByOrder(hero5);
singleLinkedList1.list();
单链表节点修改的代码实现
//修改节点的信息,根据no编号来修改,no编号不能修改
public void update(HeroNode newHeroNode) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode temp = head.next;
while(true) {
if (temp == null) {
System.out.printf("没有找到编号%d的节点,不能修改\n",newHeroNode.no);
break;
}
if (newHeroNode.no == temp.no) {
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
System.out.println("修改成功");
break;
}
temp = temp.next;
}
}
单链表删除节点
public void delete(int no ) {
HeroNode temp = head;
while(true) {
if (temp == null) {
System.out.printf("没有找到编号%d的节点,不能删除\n",no);
break;
}
// System.out.println("temp.next.no is " + temp.next.no);
if (temp.next.no == no) {
temp.next = temp.next.next;
System.out.println("删除成功");
break;
}
temp = temp.next;
}
}
题目
-
求单链表中的有效节点个数
/* * * @author * @date 2024/4/15 16:37 * @param head 链表的头节点 * @return int 有效节点个数 */ public static int getLength(HeroNode head) { if (head.next == null ) { return 0; } int length = 0; HeroNode cur = head.next; while (cur != null) { length ++; cur = cur.next; } return length; }
-
查找单链表中的倒数第k个节点
public static HeroNode findLatIndexNode(HeroNode head, int index){ if (head.next == null) { return null; } //获取链表长度 int size = getLength(head); if (index <= 0 || index > size) { return null; } HeroNode cur = head.next; for (int i = 0; i < (size - index); i++) { cur = cur.next; } return cur; }
-
单链表的反转
public static void reverseList(HeroNode head){ if (head.next == null || head.next.next == null){ return ; } HeroNode cur = head.next; HeroNode next = null; //指向当前节点[cur]的下一个节点 HeroNode reverseHead = new HeroNode(0,"",""); //遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端 while (cur != null) { next = cur.next; //先暂时保存当前节点的下一个节点 cur.next = reverseHead.next; //cur中next用于存放reverseHead中next值 reverseHead.next = cur; //将cur连到reverseHead后的第一个位置 cur = next; //让cur后移 } //将head.next指向reverseHead.next,实现单链表的反转 head.next = reverseHead.next; }
-
从尾到头打印单链表
//用栈 public static void reversePrint(HeroNode head) { if (head.next == null) { return ; } //创建一个栈,将各个节点压入栈中 Stack<HeroNode> stack = new Stack<>(); HeroNode cur = head.next; while (cur != null) { stack.push(cur); cur = cur.next; } while (stack.size()>0) { System.out.println(stack.pop()); } }
-
合并两个有序的单链表,合并之后的链表依然有序
public static HeroNode mergeDoubleList(HeroNode head1, HeroNode head2) { //TODO 如果其中一个链表为空,则直接返回另一个链表 if (head1 == null) { return head2; } if (head2 == null) { return head1; } HeroNode mergeHead = new HeroNode(0,"",""); HeroNode cur1 = head1.next; HeroNode cur2 = head2.next; HeroNode cur = mergeHead; while (cur1 != null || cur2 != null) { if (cur1 != null && cur2 != null) { if (cur1.no <= cur2.no) { cur.next = cur1; cur1 = cur1.next; } else { cur.next = cur2; cur2 = cur2.next; } } else if (cur1 == null && cur2 != null) { cur.next = cur2; cur2 = cur2.next; } else if (cur2 == null && cur1 != null) { cur.next = cur1; cur1 = cur1.next; } // cur.next.next = null; cur = cur.next; } return mergeHead; } //测试 HeroNode mergedHead = mergeDoubleList( list1.getHead(),list2.getHead() ); SingleLinkedList list3 = new SingleLinkedList(); list3.setHead( mergedHead ); list3.list();
双向链表
- 单向链表,查找的方向只能是一个方向,双向链表可以向前或者向后比较。
- 单向链表不能自我删除,需要靠辅助节点(temp待删除节点的前一个节点),双向链表可以自我删除。
package dataStructure.LinkedList;
/**
* @author
* @date 2024-04-16 20:51
*/
public class DoubleLinkedListDemo {
public static void main(String[] args) {
System.out.println("This is test");
HeroNode2 hero1 = new HeroNode2(1,"宋江","及时雨");
HeroNode2 hero2= new HeroNode2(2,"卢俊义","玉麒麟");
HeroNode2 hero3 = new HeroNode2(3,"吴用","智多星");
HeroNode2 hero4 = new HeroNode2(4,"林冲","豹子头");
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.add(hero1);
doubleLinkedList.add(hero2);
doubleLinkedList.add(hero3);
doubleLinkedList.add(hero4);
doubleLinkedList.list();
System.out.println("This is update");
HeroNode2 hero5 = new HeroNode2(4,"公孙胜","入云龙");
doubleLinkedList.update(hero5);
doubleLinkedList.list();
System.out.println("This is delete");
doubleLinkedList.delete(3);
doubleLinkedList.list();
System.out.println("This is addByOrder");
doubleLinkedList.addByOrder(hero3);
doubleLinkedList.list();
}
}
class DoubleLinkedList {
private HeroNode2 head = new HeroNode2(0,"","");
public HeroNode2 getHead() {
return head;
}
public void setHead(HeroNode2 head) {
this.head = head;
}
//添加到双向链表末尾
public void add(HeroNode2 heroNode) {
//因为head节点不能动,因此我们需要一个辅助遍历temp
HeroNode2 temp = head;
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
//当退出while循环时,temp就指向了链表的最后
//将最后这个节点的next指向新的节点
temp.next = heroNode;
heroNode.prev = temp;
}
public void addByOrder(HeroNode2 heroNode) {
//因为单链表,temp是位于添加位置的前一个节点
HeroNode2 temp = head;
boolean flag = false; //flag标志添加的编号是否存在,默认为false
while (true) {
if (temp.next == null ){
//已经到链表的最后
break;
}
if (temp.next.no > heroNode.no) {
//在temp的d当前位置添加
break;
} else if (temp.next.no == heroNode.no) {
//编号已存在
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.printf("准备插入的英雄编号 %d 已经存在",heroNode.no);
} else {
temp.next = heroNode;
heroNode.prev = temp;
}
}
//修改节点的信息,根据no编号来修改,no编号不能修改
public void update(HeroNode2 newHeroNode) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
while(true) {
if (temp == null) {
System.out.printf("没有找到编号%d的节点,不能修改\n",newHeroNode.no);
break;
}
if (newHeroNode.no == temp.no) {
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
System.out.println("修改成功");
break;
}
temp = temp.next;
}
}
public void delete(int no ) {
HeroNode2 temp = head.next;
while(true) {
if (temp == null) {
System.out.printf("没有找到编号%d的节点,不能删除\n",no);
break;
}
if (temp.no == no) {
temp.prev.next = temp.next;
//如果是最后一个节点,就不需要执行下面
if (temp.next!=null) {
temp.next.prev = temp.prev;
}
System.out.println("删除成功");
break;
}
temp = temp.next;
}
}
//遍历双向链表
//toString方法不能prev和next
public void list() {
if (head.next == null) {
System.out.println("链表为空");
return;
}
//因为头节点不能动,需要辅助变量
HeroNode2 temp = head.next;
while (true) {
//判断是否到链表最后
if (temp == null ){
break;
}
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
}
class HeroNode2 {
public int no;
public String name;
public String nickname;
public HeroNode2 prev;
public HeroNode2 next;
public HeroNode2(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "HeroNode2{" +
"no=" + no +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
单向环形链表
Josephu问题
(helper最开始指向5,first指向1)
package dataStructure.LinkedList;
public class Josephu {
public static void main(String[] args) {
CircleSingleLinkedList list = new CircleSingleLinkedList();
list.addBoy(5);
list.showBoy();
System.out.println("This is countBoy");
list.countBoy(1,2,5); //2->4->1->5->3
}
}
//创建一个环形的单向链表
class CircleSingleLinkedList {
//创建一个first节点,当前没有编号
private Boy first = new Boy(-1);
//添加小孩节点
public void addBoy(int nums) {
// nums数据校验
if (nums < 1) {
System.out.println("nums的值不正确");
return;
}
Boy curBoy = null; //辅助指针
//使用for循环创建环形链表
for (int i = 1; i <= nums ; i++) {
//根据编号创建节点
Boy boy = new Boy(i); //将要添加的boy
//如果是第一个小孩
if (i == 1) {
first = boy;
first.setNext(first);
curBoy = first;
} else {
curBoy.setNext(boy);
boy.setNext(first);
curBoy = boy;
}
}
}
//遍历
public void showBoy() {
//判断链表是否为空
if (first == null) {
System.out.println("链表为空");
return;
}
//辅助指针
Boy curBoy = first;
while(true) {
System.out.printf("小孩的编号 %d \n", curBoy.getNo());
if (curBoy.getNext() == first) {
//遍历完成
break;
}
curBoy = curBoy.getNext(); //后移
}
}
//根据用户的输入,计算出圈顺序
/*
*
* @author
* @date 2024/4/18 22:25
* @param startNo 第几个开始(先移动startNo-1次)
* @param countNum 数几下
* @param nums 表示最初有多少人
*/
public void countBoy(int startNo, int countNum, int nums){
if (first == null || startNo < 1 || startNo > nums) {
System.out.println("参数输入有误,请重新输入");
return;
}
Boy helper = first;
//创建辅助指针helper,指向环形链表的最后一个节点
while (true) {
if (helper.getNext() == first) {
//当前helper已经指向最后一个小孩了
break;
}
helper = helper.getNext();
}
//小孩报数前,先让first和helper移动k-1次
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//当小孩报数时,让first和helper指针同时的移动 m - 1次,然后出圈
//循环直到圈中只有一个节点
while (true) {
if (helper == first) {
break;
}
//让first和helper指针同时的移动 m - 1次,然后出圈
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//现在first指向的节点就是要出圈的小孩节点
System.out.printf("小孩%d出圈\n",first.getNo());
first = first.getNext(); //后移
helper.setNext(first);
}
System.out.printf("小孩%d出圈\n",first.getNo());
}
}
//表示一个节点
class Boy {
private int no; //编号
private Boy next; //指向下一个节点,默认null
public Boy(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Boy getNext() {
return next;
}
public void setNext(Boy next) {
this.next = next;
}
}