单链表进阶学习 三段
生活随笔
收集整理的這篇文章主要介紹了
单链表进阶学习 三段
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
單鏈表進階學習 三段
從尾到頭打印單鏈表:
思路:
(注:不建議直接對單鏈表進行反轉操作。這樣會破壞鏈表本身的結構,在做題和練習的時候可以嘗試,但在工作中考慮到鏈表的重復使用,最好習慣使用棧數據結構的思想來操作)
演示棧:
2.將棧元素一次性取出的操作
import java.util.Stack;public class TextStackDemo {// 演示棧的操作public static void main(String[] args) {// TODO Auto-generated method stub// 輸入“new stack()”,快捷鍵“ctrl+1”Stack<String> stack = new Stack<>();// 新建一個stack棧,標注鍵入String類型的數據// 入棧stack.add("1");stack.add("2");stack.add("3");// 鍵入棧stack三個string類型的數據// 入棧完成// 出棧// pop()直接代表出棧操作while (stack.size() > 0) {System.out.println(stack.pop());// 一次操作出棧一個數據}} }接下來進入正題:
用棧的思想解決單鏈表的逆序打印:
import java.util.Stack;public class SingleLinkedListDemo {public static void main(String[] args) {// TODO Auto-generated method stub 第一階段測試代碼// 創建節點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);// 測試單鏈表逆序功能// 顯示System.out.println("原鏈表:");singleLinkedList.list();System.out.println();System.out.println("逆序輸出的鏈表:");reversePrint(singleLinkedList.GetHead());/** //測試單鏈表反轉功能 // 顯示 System.out.println("原鏈表:"); singleLinkedList.list();* * System.out.println(); System.out.println("反轉后的鏈表:");* reverseList(singleLinkedList.GetHead()); singleLinkedList.list();* * * // 加入操作* * // singleLinkedList.add(hero1); // // singleLinkedList.add(hero2); // //* singleLinkedList.add(hero3); // // singleLinkedList.add(hero4); // //* singleLinkedList.add(hero5);* * singleLinkedList.addByOrder(hero1);* * singleLinkedList.addByOrder(hero2);* * singleLinkedList.addByOrder(hero4);* * singleLinkedList.addByOrder(hero3);* * singleLinkedList.addByOrder(hero5);* * // 修改操作 HeroNode newHeroNode = new HeroNode(5, "寫輪眼", "卡卡西");* singleLinkedList.update(newHeroNode);* * // 顯示 System.out.println("刪除前:"); singleLinkedList.list();* * // 修改操作 singleLinkedList.del(1); System.out.println("刪除后:");* singleLinkedList.list(); // 獲取單鏈表節點的個數* System.out.println(GetNumber(singleLinkedList.GetHead()));* * HeroNode res = findLastIndexNode(singleLinkedList.GetHead(), 1);// 倒數第1個* System.out.println(); System.out.println("單鏈表中倒數第index個節點 " + res);*/}// 逆序打印單鏈表public static void reversePrint(HeroNode head) {if (head.next == null) {return;// 空鏈表,無法打印}// 創建一個棧,將各節點壓入棧中Stack<HeroNode> stack = new Stack<HeroNode>();HeroNode cur = head.next;// 遍歷需要的輔助變量while (cur != null) {stack.push(cur);cur = cur.next;// 后移,好壓入下一個節點}// 出棧while (stack.size() > 0) {System.out.println(stack.pop());}}// 反轉鏈表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, "", "");// 遍歷原來的鏈表// 遍歷一個節點就將其取出,放在新建鏈表的最前端while (cur != null) {next = cur.next;// 暫時保存當前節點的下一個節點cur.next = reverseHead.next;// cur節點的下一個節點指向新鏈表的最前端reverseHead.next = cur;// 將cur連接到新的鏈表上cur = next;// cur后移}// 將原鏈表的頭節點的next指向rereverseHead的下一個節點,實現鏈表的反轉head.next = reverseHead.next;}// 1.查找單鏈表中倒數第index個節點// 2.編寫一個方法接收head節點,同時接受一個index(index數值代表單鏈表的倒數第index個節點)// 3.將鏈表遍歷一遍,得到有效節點總數(GetNumber)// 4.單鏈表有效節點總數為size,直接遍歷size-index個節點// 5.如果找到了這個節點就返回該節點,否則就返回NULLpublic static HeroNode findLastIndexNode(HeroNode head, int index) {// 如果鏈表為空返回NULLif (head.next == null) {return null;}// 第一次遍歷得到單鏈表的節點個數int size = GetNumber(head);// 第二次遍歷單鏈表,這次直接遍歷size-index個節點,這就是要求的值// 在這里要做一個index的校驗if (index <= 0 || index > size) {return null;}// 定義一個輔助變量,指向第一個有效節點(頭節點后的第一個節點)HeroNode cur = head.next;// for循環定位到倒數index個節點for (int i = 0; i < size - index; i++) {cur = cur.next;}return cur;}//獲取單鏈表節點的個數(如果帶頭結點,計數時要取消頭結點的計數,因為頭節點不存儲數據)public static int GetNumber(HeroNode head) {if (head.next == null) {return 0;}int number = 0;// 定義一個輔助變量HeroNode cur = head.next;// 這里就是沒有統計頭結點的微操作while (cur != null) {number++;cur = cur.next;}return number;} }//定義一個SingleLinkedList(單鏈表),管理英雄 class SingleLinkedList {// 一開始要初始化一個頭節點,保持不動否則會找不到剩下的節點,***不存放具體數據private HeroNode head = new HeroNode(0, "", "");// no初始化為0,姓名和稱號也不寫// 返回頭節點public HeroNode GetHead() {return head;}// 添加節點到單向鏈表// 當不考慮編號順序時:// 把節點添加進去的操作是首先找到當前鏈表的最后一個節點,next域原本是NULL,要把next域指向新添的節點public void add(HeroNode heroNode) {// 由于頭節點不能動,所以需要輔助變量HeroNode temp = head;// temp是輔助變量一開始指向頭節點,因為單向鏈表不是順序存儲,所以每一次找最后一個節點都需要遍歷整個鏈表// 開始遍歷while (true) {// 死循環if (temp.next == null) {// 找到鏈表的尾節點了break;}// 如果當前節點不是末節點// temp后移一位temp = temp.next;// 要清楚temp是一個移動輔助變量,每遍歷到一個不是尾節點的點temp就會指向當前節點的下一個節點}// 當退出這個死循環的時候,temp就指向了單鏈表的尾節點// 這個時候就可以把尾節點的next域指向傳入的新節點,這個新傳入的節點就連上了temp.next = heroNode;}// 增添節點,按照順序顯示出來// 如果已經有這個編號,則添加失敗并給出提示public void addByOrder(HeroNode heroNode) {// heroNode為傳入的新節點// 由于頭節點不能動,所以需要輔助變量// 單鏈表要添加節點,temp一定是指向要插入位置的前一個節點,然后temp.next就指向新節點,這樣第一步就完成了HeroNode temp = head;boolean flag = false;// 判斷要添加的節點是否已存在while (true) {if (temp.next == null) {break;}if (temp.next.no > heroNode.no) {break;} else if (temp.next.no == heroNode.no) {flag = true;// 說明已經有了break;} else {temp = temp.next;// 如果上述情況都不符合的話,那么繼續遍歷找下一個節點}}// 退出循環的時候要看flag的值if (flag) {System.out.printf("已有編號%d,添加失敗~~~\n", heroNode.no);} else {// 可以插入到鏈表中,temp后移heroNode.next = temp.next;// 新節點的next域指向下一個節點temp.next = heroNode;// 前一個節點的next域指向新節點}}//修改節點的信息// 根據編號no來修改稱號和姓名,編號no不動(如果編號改變就相當于添加操作了)public void update(HeroNode newHeroNode) {// 判斷鏈表是否為空if (head.next == null) {System.out.println("鏈表為空~~~");return;}// 找到需要修改的節點// 根據編號no來修改節點信息// 定義一個輔助變量HeroNode temp = head.next;boolean flag = false;// 標識是否找到這個節點while (true) {if (temp == null) {// 這里和之前不一樣,表示已經遍歷完這個鏈表了(無殘留,去干凈)break;} else if (temp.no == newHeroNode.no) {// 表示已經找到要刪除的節點flag = true;break;}temp = temp.next;}// 退出循環以后,根據flag的值來判斷if (flag) {// flag=true;表示找到了要修改的點temp.name = newHeroNode.name;temp.nickname = newHeroNode.nickname;}// 還有一種情況就是沒有找到要修改的點else {System.out.println();System.out.printf("沒有找到編號為%d 的好漢,不能刪除😔\n");}}//刪除節點/** 1.由于頭節點不能動,所以需要輔助變量,需要用輔助變量temp找到待刪除節點的前一個節點 比較時使用temp.next.no和待刪除節點的編號no比較**/public void del(int no) {HeroNode temp = head;// 因為需要找到目標節點的前一個節點,所以這里不能把輔助節點定義為頭節點之后第一個節點boolean flag = false;while (true) {if (temp.next == null) {// 到鏈表最后,最后一個節點的后面break;} else if (temp.next.no == no) {// 找到前一個節點flag = true;break;}temp = temp.next;// 每遍歷一個節點就后移一位}if (flag) {// 找到了前一個節點// 刪除操作temp.next = temp.next.next;} else {System.out.println();System.out.printf("刪除的數據%d不存在呀不存在~~~\n", no);}}// 顯示單向鏈表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);// 因為之前已經重寫過toString方法了,所以這里直接打印輸出就行了// ************// 下面這點很重要,每打印輸出一個節點,就需要將輔助變量temp后移,否則的話后果就是一直輸出一個值而且是個死循環temp = temp.next;}}}//定義HeroNode,每個HeroNode都是一個節點 class HeroNode {public int no;// 定義編號public String name;// 定義姓名public String nickname;// 定義稱號public HeroNode next;// 定義next域,指向下一個節點// 建一個構造器public HeroNode(int no, String nickname, String name) {this.no = no;this.nickname = nickname;this.name = name;}// 為了便于顯示,重寫toString方法/** @Override是偽代碼,表示重寫。(當然不寫@Override也可以),不過寫上有如下好處: 1、可以當注釋用,方便閱讀;* 2、編譯器可以給你驗證@Override下面的方法名是否是你父類中所有的,如果沒有則報錯。* 例如,你如果沒寫@Override,而你下面的方法名又寫錯了,這時你的編譯器是可以編譯通 過的,因為編譯器以為這個方法是你的子類中自己增加的方法。*/@Overridepublic String toString() {return "no= " + no + ",nickname= " + nickname + ",name = " + name;}}合并兩個單鏈表,依照順序打印輸出:
思路:
總結
以上是生活随笔為你收集整理的单链表进阶学习 三段的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2499元起!真我GT Neo5发布 首
- 下一篇: Eclipse多行注释方法