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