双向链表,又称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
单链表跟双链表的区别:
-
单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
-
单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除时节
点,总是找到temp,temp是待删除节点的前一个节点
1、双链表实现
public class DoubleLinkedList {
public static void main(String[] args) {
DoubleLinkedListD list = new DoubleLinkedListD();
HeroNode2 heroNode3 =new HeroNode2(4,"林冲","豹子头");
HeroNode2 heroNode = new HeroNode2(1, "宋江", "及时雨");
HeroNode2 heroNode1 = new HeroNode2(2, "卢俊义", "玉麒麟");
HeroNode2 heroNode2 =new HeroNode2(3,"吴用","智多星");
list.add(heroNode3);
list.add(heroNode);
list.add(heroNode1);
list.add(heroNode2);
list.List();
HeroNode2 heroNode4 = new HeroNode2(1, "xiaobear", "及时雨");
list.update(heroNode4);
list.delete(4);
list.List();
}
}
class DoubleLinkedListD{
private int length;
private HeroNode2 head = new HeroNode2(0,"","");
public HeroNode2 getHead(){
return head;
}
/**
* 显示链表
* 先判断为空,遍历后temp后移,否则就是死循环
*/
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);
temp = temp.next;
}
}
/**
* 添加节点到末尾
* 不考虑编号的顺序时,找到当前链表的最后节点,将指向最后节点的next指向新的节点
* @param heroNode2
*/
public void add(HeroNode2 heroNode2){
HeroNode2 temp = head;
/**遍历temp
* 为空,结束,不为空,指向next
*/
while (true){
if (temp.next == null) {
break;
}
temp = temp.next;
}
temp.next = heroNode2;
heroNode2.pre = temp;
length++;
}
/**
* 根据newHeroNode的no来修改
* @param newHeroNode
*/
public void update(HeroNode2 newHeroNode){
if (head.next == null){
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
boolean result = false;
while (true) {
if (temp == null){
break;
}
if (temp.no == newHeroNode.no){
result = true;
break;
}
temp = temp.next;
}
if (result) {
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
}else {
System.out.printf("没有找到编号 %d 的节点",newHeroNode.no);
}
}
/**
*删除
* result 标志是否找到
* @param no
*/
public void delete(int no) {
if (head.next == null){
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
boolean result = false;
while (true) {
if (temp == null) {
break;
}
if (temp.no == no){
result = true;
break;
}
temp = temp.next;
}
if (result) {
//temp.next = temp.next.next; 单链表
temp.pre.next = temp.next;
length--;
if (temp.next != null) {
temp.next.pre = temp.pre;
}
}else {
System.out.printf("要删除的节点 %d 不存在",no);
}
}
}
/**
* next 指向后一个节点
* pre 指向前一个节点
*/
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 "HeroNode2{" +
"no=" + no +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
2、单向环形链表
Josephu(约瑟夫、约瑟夫环) 问题
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。提示:用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
代码实现
public class Josephu {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.addBoy(99);
circleSingleLinkedList.showBoy();
circleSingleLinkedList.countBoy(10,20,99);
}
}
class CircleSingleLinkedList{
private Boy first = null;
/**
* 增加小孩节点
* @param nums
*/
public void addBoy(int nums){
if (nums < 1){
System.out.println("nums的值不正确!");
return;
}
Boy current = null;
for (int i = 1; i <= nums ; i++) {
Boy boy = new Boy(i);
if(i ==1){
first = boy;
//构成环
first.setNext(boy);
//指向第一个小孩
current = first;
}else {
current.setNext(boy);
boy.setNext(first);
current = boy;
}
}
}
public void showBoy(){
if (first == null) {
System.out.println("没有小孩");
return;
}
Boy temp = first;
while (true){
System.out.printf( "小孩的编号:%d\n",temp.getNo());
if (temp.getNext() == first){
break;
}
temp = temp.getNext();
}
}
/**
*
* @param startIndex 从第几个小孩开始计数
* @param countNum 次数
* @param nums 总小孩数
*/
public void countBoy(int startIndex,int countNum,int nums){
/**
* 数据校验
*/
if (first == null || startIndex < 0 || startIndex > nums) {
System.out.println("输入参数错误,请重新输入");
return;
}
Boy temp = first;
while (true) {
if (temp.getNext() == first){
break;
}else {
temp = temp.getNext();
}
}
for (int s = 0 ; s <startIndex - 1 ; s++) {
first = first.getNext();
temp = temp.getNext();
}
while (true) {
if (temp == first){
break;
}
for (int i = 0; i <countNum-1 ; i++) {
first = first.getNext();
temp = temp.getNext();
}
System.out.printf("小孩出圈:%d\n",first.getNo());
first = first.getNext();
temp.setNext(first);
}
System.out.printf("最后留在全中的孩子编号:%d\n",first.getNo());
}
}
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 void setNext(Boy next) {
this.next = next;
}
public Boy getNext() {
return next;
}
}