【数据结构】单向链表|双向链表|约瑟夫问题
一、单向链表
package com.serein.linkedlist;
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
HeroNode hero5 = new HeroNode(5, "燕青", "浪里白条");
SingleLinkedList singleLinkedList = new SingleLinkedList();
// singleLinkedList.add(hero1);
// singleLinkedList.add(hero2);
// singleLinkedList.add(hero3);
// singleLinkedList.add(hero4);
// singleLinkedList.add(hero5);
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero4);
singleLinkedList.addByOrder(hero3);
singleLinkedList.addByOrder(hero5);
singleLinkedList.addByOrder(hero2);
singleLinkedList.list();
HeroNode newHreo = new HeroNode(2, "小卢", "玉麒麟~~");
singleLinkedList.update(newHreo);
System.out.println("修改后的链表:");
singleLinkedList.list();
singleLinkedList.del(2);
System.out.println("删除后的链表:");
singleLinkedList.list();
int length = getLength(singleLinkedList.getHead());
System.out.println("单链表的节点个数 = " + length);
}
//有效节点个数
public static int getLength(HeroNode head) {
if (head.next == null) {
System.out.println("链表为空");
return 0;
}
HeroNode temp = head.next;
int length = 0;
while (temp != null) {
length++;
temp = temp.next;
}
return length;
}
}
//模拟一个带头的单向链表
class SingleLinkedList{
//定义一个头链表,不放数据
private HeroNode head = new HeroNode(0,null,null);
public HeroNode getHead(){
return head;
}
//添加节点
public void add(HeroNode heroNode){
//因为头结点不能动,所以定义一个临时变量辅助我们遍历链表,找到最后面的位置
HeroNode temp = head;
//用while循环遍历该链表
while (true){
if (temp.next == null){
//说明没有下一个节点了,那么就是最后一个
break;
}
//还没有到最后一个,继续后移
temp = temp.next;
}
//找到最后一个位置了,在这个位置的后面加上我们传进来的节点
temp.next = heroNode;
}
//删除节点
public void del(int no){
if (head.next == null){
System.out.println("该链表为空");
}
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.println("没有找到该节点:" + no);
}
}
//修改节点信息
public void update(HeroNode newHeroNode){
if (head.next == null){
System.out.println("链表为空,不能修改");
}
HeroNode temp = head.next;
boolean flag = false;
while (true){
if (temp.next == null){
//遍历到链表最后还没有找到,直接退出
break;
}
if (temp.next.no == newHeroNode.no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
//根据flag判断是否找到,并决定是否修改
if (flag){
temp.next.name = newHeroNode.name;
temp.next.nickName = newHeroNode.nickName;
}else {
System.out.println("不存在该节点,无法修改:" + newHeroNode.no);
}
}
//按照编号顺序添加
public void addByOrder(HeroNode heroNode){
HeroNode temp = head;
boolean flag = false;
while (true){
if (temp.next == null) {
//说明应该插入到最后面
break;
}
if (temp.next.no == heroNode.no){
//说明编号已经存在
flag = true;
break;
}else if (temp.next.no > heroNode.no){
//说明就是我们要找的位置
break;
}
//往后移,继续遍历
temp = temp.next;
}
if (flag){
System.out.println("该编号已经存在:" + heroNode.no + "不能插入");
}else {
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//遍历显示该链表
public void list(){
//判断链表是否为空
if (head.next == null){
System.out.println("链表为空");
return;
}
//头结点不能动,定义一个临时变量辅助遍历
HeroNode temp = head;
while (true){
if (temp.next == null){
break;
}
//说明没到最后一个元素
System.out.println(temp.next);
temp = temp.next;
}
}
}
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 +
'}';
}
// @Override
// public String toString() {
// return "HeroNode{" +
// "no=" + no +
// ", name='" + name + '\'' +
// ", nickName='" + nickName + '\'' +
// ", next=" + next +
// '}';
// }
// @Override
// public String toString() {
// return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickName + "]";
// }
}
二、双向链表
package com.serein.linkedlist;
/**
* @author baichuan
* @version 1.0
*/
public class DoubleLinkedListDemo {
public static void main(String[] args) {
HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨");
HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");
HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星");
HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");
HeroNode2 hero5 = new HeroNode2(5, "燕青", "浪里白条");
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.addByOrder(hero1);
doubleLinkedList.addByOrder(hero5);
doubleLinkedList.addByOrder(hero3);
doubleLinkedList.addByOrder(hero4);
doubleLinkedList.addByOrder(hero2);
doubleLinkedList.del(2);
HeroNode2 heroNode2 = new HeroNode2(1, "小宋", "及时雨~~");
doubleLinkedList.update(heroNode2);
doubleLinkedList.list();
}
}
class DoubleLinkedList{
private HeroNode2 head = new HeroNode2(0,null,null);
public HeroNode2 getHead(){
return head;
}
public void list(){
//判断链表是否为空
if (head.next == null){
System.out.println("链表为空");
return;
}
//头结点不能动,定义一个临时变量辅助遍历
HeroNode2 temp = head;
while (true){
if (temp.next == null){
break;
}
//说明没到最后一个元素
System.out.println(temp.next);
temp = temp.next;
}
}
public void addByOrder(HeroNode2 heroNode){
HeroNode2 temp = head;
boolean flag = false;
while (true){
if (temp.next == null) {
//说明应该插入到最后面
break;
}
if (temp.next.no == heroNode.no){
//说明编号已经存在
flag = true;
break;
}else if (temp.next.no > heroNode.no){
//说明就是我们要找的位置
break;
}
//往后移,继续遍历
temp = temp.next;
}
if (flag){
System.out.println("该编号已经存在:" + heroNode.no + "不能插入");
}else {
heroNode.next = temp.next;
temp.next = heroNode;
heroNode.pre = temp;
}
}
//修改节点信息
public void update(HeroNode2 newHeroNode){
if (head.next == null){
System.out.println("链表为空,不能修改");
}
HeroNode2 temp = head;
boolean flag = false;
while (true){
if (temp.next == null){
//遍历到链表最后还没有找到,直接退出
break;
}
if (temp.next.no == newHeroNode.no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
//根据flag判断是否找到,并决定是否修改
if (flag){
temp.next.name = newHeroNode.name;
temp.next.nickName = newHeroNode.nickName;
}else {
System.out.println("不存在该节点,无法修改:" + newHeroNode.no);
}
}
public void add(HeroNode2 heroNode){
//因为头结点不能动,所以定义一个临时变量辅助我们遍历链表,找到最后面的位置
HeroNode2 temp = head;
//用while循环遍历该链表
while (true){
if (temp.next == null){
//说明没有下一个节点了,那么就是最后一个
break;
}
//还没有到最后一个,继续后移
temp = temp.next;
}
//找到最后一个位置了,在这个位置的后面加上我们传进来的节点
temp.next = heroNode;
heroNode.pre = temp;
}
//删除节点
public void del(int no){
if (head.next == null){
System.out.println("该链表为空");
}
HeroNode2 temp = head.next;
boolean flag = false;
while (true){
if (temp == null){
//遍历到最后一个位置了
break;
}
if (temp.no == no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.pre.next = temp.next;
if (temp.next != null) {
temp.next.pre = temp.pre;
}
}else {
System.out.println("没有找到该节点:" + no);
}
}
}
class HeroNode2{
public int no;
public String name;
public String nickName;
public HeroNode2 next;
public HeroNode2 pre;
public HeroNode2(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 +
'}';
}
}
约瑟夫问题
package com.serein.linkedlist;
/**
* @author baichuan
* @version 1.0
*/
public class Josephus {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.addBoy(5);
circleSingleLinkedList.showBoy();
System.out.println("出圈游戏:");
circleSingleLinkedList.countBoy(1,2,5);
}
}
class CircleSingleLinkedList{
//定义一个头结点
private Boy first = null;
/**
* 小孩出圈的方法
* @param startNo 开始报数的小孩
* @param countNum 一次报几个数
* @param nums 有多少个小孩
*/
public void countBoy(int startNo,int countNum,int nums){
//数据校验
if (first == null || nums == 1 || startNo < 0){
System.out.println("数据输入有误");
return;
}
//定义一个辅助指针来遍历
Boy helper = first;
//让helper指向最后一个节点
while (true){
if (helper.getNext() == first){
break;
}
helper = helper.getNext();
}
//报数前,让first 和helper 移动startNo - 1次,因为不一定是从第一个小孩开始报数
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//报数时,first 和helper 同时移动countNum - 1 次
//first是一个指针。意思是:从谁开始报数,是变化的。helper要指向出圈小孩的前一个位置,然后和出圈小孩下一个节点连接
while (true){
if (first == helper){
//只有一个节点了
break;
}
// helper要指向出圈小孩的前一个位置
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//位置也移动了,该出圈了
System.out.println("出圈的小孩是:" + first.getNo());
//出圈后,形成新的环
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后留在圈中的小孩:" + first.getNo());
}
//遍历环形链表的方法
public void showBoy(){
//判断链表是否为空
if (first == null){
System.out.println("链表为空");
return;
}
Boy curBoy = first;
while (true){
System.out.println("小孩的编号是:" + curBoy.getNo());
if (curBoy.getNext() == first){
//说明已经遍历一圈了
break;
}
//走一遍流程后 指针要后移一位,不然永远是死循环
curBoy = curBoy.getNext();
}
}
//添加元素的方法
public void addBoy(int nums){
//定义一个临时变量辅助遍历
Boy curBoy = null;
//判断编号是否正确
if (nums < 1){
System.out.println("编号不正确,无法添加");
return;
}
//用for循环创建环形链表
for (int i = 1; i <= nums; i++) {
Boy boy = new Boy(i);
//如果是添加第一个元素
if (i == 1){
first = boy;//小孩指向第一个位置
boy.setNext(first);//自己指向自己,形成环
curBoy = first;//辅助节点移位置,以便下一次用
}else {//正常逻辑
//辅助节点断开连接,指向新加入的节点
curBoy.setNext(boy);
//新加入的节点指向开头,形成环
boy.setNext(first);
//辅助节点移位置,以便下一次用
curBoy = boy;
}
}
}
}
class Boy{
private int no;
//指向下一个节点
private Boy next;
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;
}
}