雙向鏈表的遍歷,添加,修改,刪除的操做思路,代碼實現算法
public class DoubleLinkedListDemo {
public static void main(String[] args) {
// 測試
System.out.println("雙向鏈表的測試");
// 先建立節點
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();
// 修改
HeroNode2 newHeroNode = new HeroNode2(4, "公孫勝", "入雲龍");
doubleLinkedList.update(newHeroNode);
System.out.println("修改後的鏈表狀況");
doubleLinkedList.list();
// 刪除
doubleLinkedList.del(3);
System.out.println("刪除後的鏈表狀況~~");
doubleLinkedList.list();
}
}
// 建立一個雙向鏈表的類
class DoubleLinkedList {
// 先初始化一個頭節點, 頭節點不要動, 不存放具體的數據
private HeroNode2 head = new HeroNode2(0, "", "");
// 返回頭節點
public HeroNode2 getHead() {
return head;
}
// 遍歷雙向鏈表的方法
// 顯示鏈表[遍歷]
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 = temp.next;
}
}
// 添加一個節點到雙向鏈表的最後.
public void add(HeroNode2 heroNode) {
// 由於head節點不能動,所以咱們須要一個輔助遍歷 temp
HeroNode2 temp = head;
// 遍歷鏈表,找到最後
while (true) {
// 找到鏈表的最後
if (temp.next == null) {//
break;
}
// 若是沒有找到最後, 將將temp後移
temp = temp.next;
}
// 當退出while循環時,temp就指向了鏈表的最後
// 造成一個雙向鏈表
temp.next = heroNode;
heroNode.pre = temp;
}
// 修改一個節點的內容, 能夠看到雙向鏈表的節點內容修改和單向鏈表同樣
// 只是 節點類型改爲 HeroNode2
public void update(HeroNode2 newHeroNode) {
// 判斷是否空
if (head.next == null) {
System.out.println("鏈表爲空~");
return;
}
// 找到須要修改的節點, 根據no編號
// 定義一個輔助變量
HeroNode2 temp = head.next;
boolean flag = false; // 表示是否找到該節點
while (true) {
if (temp == null) {
break; // 已經遍歷完鏈表
}
if (temp.no == newHeroNode.no) {
// 找到
flag = true;
break;
}
temp = temp.next;
}
// 根據flag 判斷是否找到要修改的節點
if (flag) {
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
} else { // 沒有找到
System.out.printf("沒有找到 編號 %d 的節點,不能修改\n", newHeroNode.no);
}
}
// 從雙向鏈表中刪除一個節點,
// 說明
// 1 對於雙向鏈表,咱們能夠直接找到要刪除的這個節點
// 2 找到後,自我刪除便可
public void del(int no) {
// 判斷當前鏈表是否爲空
if (head.next == null) {// 空鏈表
System.out.println("鏈表爲空,沒法刪除");
return;
}
HeroNode2 temp = head.next; // 輔助變量(指針)
boolean flag = false; // 標誌是否找到待刪除節點的
while (true) {
if (temp == null) { // 已經到鏈表的最後
break;
}
if (temp.no == no) {
// 找到的待刪除節點的前一個節點temp
flag = true;
break;
}
temp = temp.next; // temp後移,遍歷
}
// 判斷flag
if (flag) { // 找到
// 能夠刪除
// temp.next = temp.next.next;[單向鏈表]
temp.pre.next = temp.next;
// 這裏咱們的代碼有問題?
// 若是是最後一個節點,就不須要執行下面這句話,不然出現空指針
if (temp.next != null) {
temp.next.pre = temp.pre;
}
} else {
System.out.printf("要刪除的 %d 節點不存在\n", no);
}
}
}
// 定義HeroNode2 , 每一個HeroNode 對象就是一個節點
class HeroNode2 {
public int no;
public String name;
public String nickname;
public HeroNode2 next; // 指向下一個節點, 默認爲null
public HeroNode2 pre; // 指向前一個節點, 默認爲null
// 構造器
public HeroNode2(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
// 爲了顯示方法,咱們從新toString
@Override
public String toString() {
return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
}
}
複製代碼
Josephu 問題爲:設編號爲1,2,…n的n我的圍坐一圈,約定編號爲k(1<=k<=n)的人從1開始報數,數到m 的那我的出列,它的下一位又從1開始報數,數到m的那我的又出列,依次類推,直到全部人出列爲止,由此產生一個出隊編號的序列。bash
用一個不帶頭結點的循環鏈表來處理Josephu問題:先構成一個有n個結點的單循環鏈表,而後由k結點起從1開始計數,計到m時,對應結點從鏈表中刪除,而後再從被刪除結點的下一個結點又從1開始計數,直到最後一個結點從鏈表中刪除算法結束。ide
例: n = 5 , 即有5我的 。 k = 1, 從第一我的開始報數。 m = 2, 數2下。測試
n = 5 , 即有5我的ui
k = 1, 從第一我的開始報數this
m = 2, 數2下spa
// 建立一個Boy類,表示一個節點
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;
}
}
複製代碼
// 建立一個環形的單向鏈表
class CircleSingleLinkedList {
// 建立一個first節點,當前沒有編號
private Boy first = null;
// 添加小孩節點,構建成一個環形的鏈表
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);
// 若是是第一個小孩
if (i == 1) {
first = boy;
first.setNext(first); // 構成環
curBoy = first; // 讓curBoy指向第一個小孩
} else {
curBoy.setNext(boy);//
boy.setNext(first);//
curBoy = boy;
}
}
}
// 遍歷當前的環形鏈表
public void showBoy() {
// 判斷鏈表是否爲空
if (first == null) {
System.out.println("沒有任何小孩~~");
return;
}
// 由於first不能動,所以咱們仍然使用一個輔助指針完成遍歷
Boy curBoy = first;
while (true) {
System.out.printf("小孩的編號 %d \n", curBoy.getNo());
if (curBoy.getNext() == first) {// 說明已經遍歷完畢
break;
}
curBoy = curBoy.getNext(); // curBoy後移
}
}
// 根據用戶的輸入,計算出小孩出圈的順序
/**
* @param startNo 表示從第幾個小孩開始數數
* @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 j = 0; j < startNo - 1; j++) {
first = first.getNext();
helper = helper.getNext();
}
//當小孩報數時,讓first 和 helper 指針同時 的移動 m - 1 次, 而後出圈
//這裏是一個循環操做,知道圈中只有一個節點
while(true) {
if(helper == first) { //說明圈中只有一個節點
break;
}
//讓 first 和 helper 指針同時 的移動 countNum - 1
for(int j = 0; j < countNum - 1; j++) {
first = first.getNext();
helper = helper.getNext();
}
//這時first指向的節點,就是要出圈的小孩節點
System.out.printf("小孩%d出圈\n", first.getNo());
//這時將first指向的小孩節點出圈
first = first.getNext();
helper.setNext(first); //
}
System.out.printf("最後留在圈中的小孩編號%d \n", first.getNo());
}
}
複製代碼
//測試
public class Josepfu {
public static void main(String[] args) {
// 測試一把看看構建環形鏈表,和遍歷是否ok
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.addBoy(125);// 加入5個小孩節點
circleSingleLinkedList.showBoy();
//測試一把小孩出圈是否正確
circleSingleLinkedList.countBoy(10, 20, 125); // 2->4->1->5->3
//String str = "7*2*2-5+1-5+3-3";
}
}
複製代碼