(数据结构与算法)单链表与双链表增删改查的实现。
生活随笔
收集整理的這篇文章主要介紹了
(数据结构与算法)单链表与双链表增删改查的实现。
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 鏈表介紹
- 1. 單鏈表應用實例
- 1.1 實現思路
- 1.2 代碼實現
- 2.單鏈表常見面試題
- 2.1 求單鏈表中有效節點的個數
- 2.2 查找單鏈表中倒數第K個節點
- 2.3 單鏈表的反轉
- 2.4 逆序打印單鏈表
- 2.5 合并兩個單鏈表,合并后依然有序
- 3. 雙鏈表應用實例
- 3.1 單鏈表缺點
- 3.2 實現思路
- 3.3 代碼實現
鏈表介紹
鏈表是有序的列表,但是它在內存中是如下存儲的:
- 鏈表是以節點的方式來存儲,是鏈式存儲
- 每個節點包含data域,next域:指向下一個節點
- 鏈表的各個節點不一定是連續存儲
- 鏈表分帶頭節點的鏈表和沒有頭結點的鏈表
單鏈表(帶頭節點)邏輯結構示意圖如下:
1. 單鏈表應用實例
使用帶頭的單向鏈表實現 -帶編號的英雄人物的增刪改查操作。
1.1 實現思路
1.add方法添加英雄時,直接添加到鏈表尾部
2.addByOrder方法添加英雄時,根據英雄編號將英雄插入到指定的位置
3.update方法修改節點功能。
1)通過遍歷根據no找到該節點,沒找到就后移temp=temp.next
2)替換name和nickName
4.刪除節點
1.2 代碼實現
package com.zh.LinkedList;public class SingleLinkedListDemo01 {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,"盧錫安","圣槍游俠");SingleLinkedList list = new SingleLinkedList(); // list.add(hero1); // list.add(hero2); // list.add(hero3); // list.add(hero4); // list.listTraverse();list.addByOrder(hero1);list.addByOrder(hero4);list.addByOrder(hero3);list.addByOrder(hero2);list.listTraverse();HeroNode heroNew = new HeroNode(2,"佐伊","暮光星靈");list.update(heroNew);System.out.println("-------------------修改后------------------");list.listTraverse();list.delete(1);System.out.println("-------------------刪除后------------------");list.listTraverse();} }//創建鏈表 class SingleLinkedList{//創建一個頭節點,頭節點不能動,不存放具體的數據HeroNode head = new HeroNode(0,"","");/*當不考慮編號順序時1.找到當前鏈表的最后節點2.將最后這個節點的next指向新的節點*/public void add(HeroNode heroNode){//因為頭節點不能動,所以創建一個輔助節點tempHeroNode temp = head;while (true){//找到鏈表的最后節點if (temp.next==null){break;}else {//如果沒有找到鏈表的最后,后移一位temp = temp.next;}}//將最后這個節點的next指向新的節點temp.next=heroNode;}//按英雄編號來添加public void addByOrder(HeroNode heroNode){HeroNode temp = head;boolean flag = false;//判斷添加的節點是否存在while (true){if (temp.next==null){//鏈表為空break;}if (temp.next.no > heroNode.no){//如果temp指向的下一個節點編號大于添加的編號,說明新節點位于temp與temp.next之間break;}else if (temp.next.no == heroNode.no){//說明添加的節點編號已經存在flag = true;break;}//節點后移temp = temp.next;}if (flag){System.out.println("要添加的節點已存在,編號為"+heroNode.no);}else {//插入到鏈表中,將新節點的next指向temp.next,temp.next指向新節點heroNode.next = temp.next;temp.next = heroNode;}}//鏈表節點修改public void update(HeroNode heroNode){//判斷是否為空if (head.next==null){System.out.println("鏈表為空");return;}//根據no找到要修改的節點//定義輔助變量HeroNode temp = head.next;boolean flag = false;//表示是否找到該節點while (true){if (temp==null){//已經遍歷完break;}if (temp.no == heroNode.no){flag = true;break;}//沒找到就后移temp = temp.next;}if (flag) {temp.name = heroNode.name;temp.nickName = heroNode.nickName;}else {System.out.println("沒有找到編號為"+ heroNode.no+"的節點,不能進行修改");}}//刪除節點public void delete(int no){HeroNode temp = head;boolean flag = false;if (head.next==null){System.out.println("鏈表為空");}while (true){if (temp.next==null){//已經遍歷完break;}if (temp.next.no==no){flag = true;break;}temp = temp.next;}if (flag){temp.next = temp.next.next;}else {System.out.println("沒有找到編號為"+no+"的節點,無法刪除");}}//鏈表遍歷public void listTraverse(){//創建一個輔助節點遍歷HeroNode temp = head.next;//判斷鏈表是否為空if (temp==null){System.out.println("鏈表為空");return;}else {while (true){//判斷鏈表是否到最后if (temp == null){break;}else{//輸出節點信息System.out.println(temp);//將節點后移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;}@Overridepublic String toString() {return "HeroNode{" +"no=" + no +", name='" + name + '\'' +", nickName='" + nickName + '\'' +'}';} }2.單鏈表常見面試題
2.1 求單鏈表中有效節點的個數
/**獲取單鏈表有效節點的個數** @param head* @return*/public int getLength(HeroNode head){int length = 0;HeroNode temp = head;if (head.next==null){return 0;}while (temp.next!=null){length++;temp = temp.next;}return length;}2.2 查找單鏈表中倒數第K個節點
/*** 查找鏈表中倒數第K個節點* @param head* @param index* @return*/public HeroNode findLastIndexNode(HeroNode head,int index){//index表示倒數第index個節點//獲取鏈表長度int length = getLength(head);HeroNode temp = head.next;if (head.next==null){return null;}//從第一個開始遍歷length - index就可以得到倒數第index個節點int signal = length - index;if (index <= 0 || index > length){return null;}for (int i = 0; i <signal ; i++) {temp=temp.next;}return temp;}2.3 單鏈表的反轉
思路:
2.4 逆序打印單鏈表
要求:反向遍歷,用棧實現
/*** 單鏈表逆序輸出(用棧實現)* @param head*/public void reversePrint(HeroNode head){if (head.next==null){return;}HeroNode cur = head.next;Stack<HeroNode> stack = new Stack<>();while (cur!=null){stack.add(cur);//將鏈表的節點壓入棧cur = cur.next;}while (stack.size()>0){System.out.println(stack.pop());//先進后出輸出}}2.5 合并兩個單鏈表,合并后依然有序
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {if (l1 == null) return l2;if (l2 == null) return l1;ListNode head = null;if (l1.val <= l2.val){head = l1;head.next = mergeTwoLists(l1.next, l2);} else {head = l2;head.next = mergeTwoLists(l1, l2.next);}return head; }3. 雙鏈表應用實例
3.1 單鏈表缺點
管理單向鏈表的缺點分析:
下面用雙鏈表來實現上面的增刪改查功能。
3.2 實現思路
遍歷:和單鏈表一樣,但是既可以向前遍歷也可以向后遍歷
添加(默認添加到雙向鏈表最后): 先找到雙向鏈表最后的一個節點
修改 :和單鏈表思路一樣
刪除:因為是雙向鏈表,所以可以自我刪除,直接找到要刪除的節點
3.3 代碼實現
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 hero2New = new HeroNode2(2,"佐伊","暮光星靈");DoubleLinkedList list = new DoubleLinkedList();//添加節點list.add(hero1);list.add(hero2);list.add(hero3);list.add(hero4);System.out.println("----------------遍歷-----------------");list.traverse();System.out.println("----------------修改后-----------------");list.update(hero2New);list.traverse();System.out.println("----------------刪除后-----------------");list.del(3);list.traverse();}} class DoubleLinkedList{//創建一個頭節點,頭節點不能動,不存放具體的數據private HeroNode2 head = new HeroNode2(0,"","");public void setHead(HeroNode2 head) {this.head = head;}public HeroNode2 getHead() {return head;}/*** 在鏈表的最后添加節點*/public void add(HeroNode2 heroNode){//頭結點不能動,創建一個輔助節點HeroNode2 temp = head;//找到最后一個節點while (temp.next!=null){temp = temp.next;}//將新節點添加到節點的最后temp.next = heroNode;heroNode.pre = temp;}/*** 遍歷鏈表*/public void traverse(){if (head.next == null){System.out.println("鏈表為空");return;}HeroNode2 temp = head.next;while (temp!=null){System.out.println(temp);temp=temp.next;}}/*** 修改鏈表節點*/// 修改一個節點的內容, 可以看到雙向鏈表的節點內容修改和單向鏈表一樣// 只是 節點類型改成 HeroNode2public 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);}}/*** 刪除節點*/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) {flag = true;break;}temp = temp.next; // temp后移,遍歷}// 判斷flagif (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);}} } 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;}@Overridepublic String toString() {return "HeroNode{" +"no=" + no +", name='" + name + '\'' +", nickName='" + nickName + '\'' +'}';} }總結
以上是生活随笔為你收集整理的(数据结构与算法)单链表与双链表增删改查的实现。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (数据结构与算法)数组模拟队列和环形队列
- 下一篇: (数据结构与算法)单向环形链表解决约瑟夫