最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)與面試題匯總

 更新時(shí)間:2022年10月25日 11:13:40   作者:興趣使然黃小黃  
由于順序表的插入刪除操作需要移動(dòng)大量的元素,影響了運(yùn)行效率,因此引入了線性表的鏈?zhǔn)酱鎯?chǔ)——單鏈表。本文為大家介紹了單鏈表的實(shí)現(xiàn)與面試題匯總,感興趣的可以了解一下

1 單鏈表

1.1 單鏈表介紹

由于順序表的插入刪除操作需要移動(dòng)大量的元素,影響了運(yùn)行效率,因此引入了線性表的鏈?zhǔn)酱鎯?chǔ)——單鏈表。單鏈表通過一組任意的存儲(chǔ)單元來存儲(chǔ)線性表中的數(shù)據(jù)元素,不需要使用地址連續(xù)的存儲(chǔ)單元,因此它 不要求在邏輯上相鄰的兩個(gè)元素在物理位置上也相鄰。

物理結(jié)構(gòu)示意圖:

邏輯結(jié)構(gòu)示意圖:

關(guān)于單鏈表的一些說明:

  • 鏈表是以節(jié)點(diǎn)的方式存儲(chǔ)的,每個(gè)節(jié)點(diǎn)包含data和next域,分別表示存儲(chǔ)的數(shù)據(jù)和指向下一個(gè)節(jié)點(diǎn);
  • 鏈表的各個(gè)節(jié)點(diǎn)不一定是連續(xù)存儲(chǔ)的;
  • 可以根據(jù)實(shí)際需求來構(gòu)造是否帶有頭節(jié)點(diǎn)的鏈表。

1.2 單鏈表的實(shí)現(xiàn)思路分析

1.2.1 單鏈表的創(chuàng)建與遍歷

單鏈表的創(chuàng)建:

先創(chuàng)建一個(gè) head 頭節(jié)點(diǎn),表示單鏈表的頭;

每添加一個(gè)節(jié)點(diǎn)就直接加入鏈表的最后;

遍歷的思路:

創(chuàng)建一個(gè)輔助指針,用于幫助遍歷整個(gè)鏈表;

當(dāng)指針指向的節(jié)點(diǎn)的next域?yàn)閚ull,說明當(dāng)前節(jié)點(diǎn)為最后一個(gè),遍歷完成。 1.2.2 單鏈表節(jié)點(diǎn)的插入與修改

示意圖如下:

  • 首先需要通過遍歷找到需要添加節(jié)點(diǎn)的位置,圖中示意的為a1的位置;
  • 新的節(jié)點(diǎn)的next指向a1.next;
  • 將該位置,即a1.next指向新的節(jié)點(diǎn)。

修改操作相當(dāng)于上述過程的簡化,只需要找到對(duì)應(yīng)的節(jié)點(diǎn)直接修改節(jié)點(diǎn)對(duì)應(yīng)的屬性即可,這里不再贅述。

1.2.3 單鏈表節(jié)點(diǎn)的刪除

刪除序號(hào)為 “2” 的節(jié)點(diǎn)示意圖如下:

思路如下:

  • 找到待刪除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn),示例中則找到序號(hào)為1的節(jié)點(diǎn);
  • 讓該節(jié)點(diǎn)的 temp.next = temp.next.next,即可;
  • 由于被刪除的節(jié)點(diǎn)沒有其他的指向,則會(huì)由Java的垃圾回收機(jī)制進(jìn)行回收,無需處理。

1.3 實(shí)現(xiàn)代碼

StudentNode.java 節(jié)點(diǎn)類:

/**
 * @author 興趣使然黃小黃
 * @version 1.0
 * 鏈表的節(jié)點(diǎn)類,包含學(xué)生信息和next
 */
public class StudentNode {
    public String no; //學(xué)號(hào)
    public String name; //姓名
    public int age; //年齡
    public StudentNode next; //指向下一個(gè)節(jié)點(diǎn)

    //構(gòu)造器
    public StudentNode(String no, String name, int age ){
        this.no = no;
        this.name = name;
        this.age = age;
    }

    //為了顯示方便
    @Override
    public String toString() {
        return "StudentNode{" +
                "no='" + no + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

StudentLinkedList.java 鏈表的實(shí)現(xiàn)類:

/**
 * @author 興趣使然黃小黃
 * @version 1.0
 * 鏈表的實(shí)現(xiàn)類,用于管理眾多StudentNode節(jié)點(diǎn)
 */
public class StudentLinkedList {
    //初始化頭節(jié)點(diǎn)
    private StudentNode head = new StudentNode("", "", 0);

	  //獲取頭節(jié)點(diǎn)
    public StudentNode getHead() {
        return head;
    }

    //添加節(jié)點(diǎn)
    //1.找到當(dāng)前鏈表的最后節(jié)點(diǎn)
    //2.將最后節(jié)點(diǎn)的next指向新的節(jié)點(diǎn)
    public void add(StudentNode studentNode) {
        StudentNode temp = head;
        //遍歷鏈表找到最后的節(jié)點(diǎn)
        while (temp.next != null) {
            //沒有找到,就后移
            temp = temp.next;
        }
        //最后的節(jié)點(diǎn)的next指向新節(jié)點(diǎn)
        temp.next = studentNode;
    }

    //遍歷 顯示鏈表
    public void showList(){
        //判斷鏈表是否為空
        if (head.next == null){
            System.out.println("當(dāng)前鏈表為空");
            return;
        }
        //遍歷 使用輔助指針
        StudentNode temp = head;
        while (temp != null){
            //更新指針
            temp = temp.next;
            if (temp.next == null){
                System.out.print(temp);
                break;
            }
            System.out.print(temp + "--->");
        }
    }

    //插入節(jié)點(diǎn)
    //根據(jù)學(xué)號(hào)順序查找添加的位置, 如果存在, 則提示錯(cuò)誤信息
    public void addByOrder(StudentNode studentNode){
        //尋找的temp應(yīng)該為添加位置的前一個(gè)節(jié)點(diǎn)
        StudentNode temp = head;
        boolean flag = false; //標(biāo)識(shí)新添加的no是否已經(jīng)存在
        while (true){
            if (temp.next == null){
                //已經(jīng)在鏈表的尾部
                break;
            }
            if (Integer.parseInt(temp.next.no) > Integer.parseInt(studentNode.no)){
                //位置找到 插入到temp后
                break;
            }else if (Integer.parseInt(temp.next.no) == Integer.parseInt(studentNode.no)){
                //已經(jīng)存在
                flag = true;
                break;
            }
            //移動(dòng)指針
            temp = temp.next;
        }
        if (flag){
            System.out.println("\n準(zhǔn)備插入的學(xué)生信息: " + studentNode.no + ",該學(xué)號(hào)已經(jīng)存在,不可添加!");
        }else {
            studentNode.next = temp.next;
            temp.next = studentNode;
        }
    }

    //根據(jù)no學(xué)號(hào)修改學(xué)生信息
    public void update(StudentNode studentNode){
        if (head.next == null){
            System.out.println("當(dāng)前鏈表為空, 無法修改");
            return;
        }
        StudentNode temp = head.next;
        boolean flag = false; //表示是否找到節(jié)點(diǎn)
        while (true){
            if (temp == null){
                break;
            }
            if (temp.no == studentNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.name = studentNode.name;
            temp.age = studentNode.age;
        }else {
            System.out.println("沒有找到");
        }
    }

    //刪除節(jié)點(diǎn)
    public void delete(String no){
        StudentNode temp = head;
        boolean flag = false; //標(biāo)志是否找到
        //查找到待刪除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)進(jìn)行刪除操作
        while (true){
            if (temp.next == null){
                //到達(dá)尾部
                break;
            }
            if (temp.next.no == no){
                //找到了
                flag = true;
                break;
            }
            //遍歷
            temp = temp.next;
        }
        //刪除操作
        if (flag){
            temp.next = temp.next.next;
            System.out.println("刪除成功!");
        }else {
            System.out.println("要?jiǎng)h除的節(jié)點(diǎn)不存在!");
        }
    }
}

測試類:

/**
 * @author 興趣使然黃小黃
 * @version 1.0
 * 測試鏈表
 */
public class StudentListTest {

    public static void main(String[] args) {
        StudentNode node1 = new StudentNode("1", "黃小黃", 21);
        StudentNode node2 = new StudentNode("2", "懶羊羊", 21);
        StudentNode node3 = new StudentNode("3", "沸羊羊", 22);
        //創(chuàng)建單鏈表 錄入數(shù)據(jù) 輸出
        StudentLinkedList list = new StudentLinkedList();
        list.add(node1);
        list.add(node2);
        list.add(node3);
        System.out.println("遍歷鏈表:");
        list.showList();
        //測試插入數(shù)據(jù)方法
        StudentNode node5 = new StudentNode("5", "美羊羊", 19);
        StudentNode node4 = new StudentNode("4", "暖羊羊", 19);
        list.addByOrder(node5);
        list.addByOrder(node4);
        System.out.println("\n依次插入學(xué)號(hào)為5、4的學(xué)生后:");
        list.showList();
        //測試修改方法
        System.out.println("\n測試修改方法:");
        list.update(new StudentNode("1", "禰豆子", 10));
        list.showList();
        //測試刪除方法
        System.out.println("\n測試刪除方法:");
        list.delete("1");
        list.delete("5");
        list.showList();
    }
}

實(shí)現(xiàn)結(jié)果:

遍歷鏈表:
StudentNode{no='1', name='黃小黃', age=21}--->StudentNode{no='2', name='懶羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}
依次插入學(xué)號(hào)為5、4的學(xué)生后:
StudentNode{no='1', name='黃小黃', age=21}--->StudentNode{no='2', name='懶羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}--->StudentNode{no='4', name='暖羊羊', age=19}--->StudentNode{no='5', name='美羊羊', age=19}
測試修改方法:
StudentNode{no='1', name='禰豆子', age=10}--->StudentNode{no='2', name='懶羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}--->StudentNode{no='4', name='暖羊羊', age=19}--->StudentNode{no='5', name='美羊羊', age=19}
測試刪除方法:
刪除成功!
刪除成功!
StudentNode{no='2', name='懶羊羊', age=21}--->StudentNode{no='3', name='沸羊羊', age=22}--->StudentNode{no='4', name='暖羊羊', age=19}
Process finished with exit code 0

2 單鏈表的面試題

2.1 統(tǒng)計(jì)單鏈表中有效節(jié)點(diǎn)數(shù)量

 /**
     * 
     * @param head 頭節(jié)點(diǎn)
     * @return 返回有效節(jié)點(diǎn)個(gè)數(shù)
     */
    public static int getLength(StudentNode head){
        if (head.next == null){
            return 0;
        }
        int length = 0;
        StudentNode temp = head.next;
        while (temp != null){
            length++;
            temp = temp.next;
        }
        return length;
    }

2.2 新浪–倒數(shù)第k個(gè)節(jié)點(diǎn)

查找鏈表中倒數(shù)第k個(gè)節(jié)點(diǎn)

思路分析:

  • 編寫一個(gè)方法,接收head頭節(jié)點(diǎn)和index,index表示k;
  • 鏈表從頭到尾遍歷,求出長度(鏈表節(jié)點(diǎn)個(gè)數(shù))size;
  • 從第一個(gè)節(jié)點(diǎn),遍歷size-length次,即可找到倒數(shù)第k個(gè)節(jié)點(diǎn)。

參考代碼:

/**
     * 獲取單鏈表中倒數(shù)第k個(gè)節(jié)點(diǎn)
     * @param head 鏈表的頭節(jié)點(diǎn)
     * @param index 倒數(shù)第 k 個(gè)元素
     * @return 返回倒數(shù)第 k 個(gè)元素,或者 null
     */
    public static StudentNode findLastIndexNode(StudentNode head, int index){
        //如果鏈表為空
        if (head.next == null){
            return null;
        }
        //得到鏈表的長度(節(jié)點(diǎn)個(gè)數(shù))
        int size = getLength(head);
        //遍歷 size-index次 得到倒數(shù)第index個(gè)節(jié)點(diǎn)
        //數(shù)據(jù)校驗(yàn)
        if (index <= 0 || index > size){
            return null;
        }
        //遍歷
        StudentNode current = head.next;
        for (int i = 0; i < size - index; i++) {
            current = current.next;
        }
        return current;
    }

2.3 騰訊–單鏈表的反轉(zhuǎn)

反轉(zhuǎn)單鏈表

思路分析:

  • 可以使用頭插法;
  • 以原鏈表為模板,每遍歷一個(gè)節(jié)點(diǎn),取出,并接在新鏈表的最前端;
  • 原h(huán)ead頭節(jié)點(diǎn),指向新的節(jié)點(diǎn);
  • 直到遍歷完為止。

參考代碼:

	/**
     * 頭插法反轉(zhuǎn)鏈表
     * @param head 接收待反轉(zhuǎn)的鏈表
     * @return 返回一個(gè)反轉(zhuǎn)后的新鏈表
     */
    public static StudentLinkedList reverseList(StudentNode head){
        if (head.next == null){
            return null;
        }
        StudentNode old = head.next; //用于遍歷舊鏈表
        //創(chuàng)建新鏈表,新鏈表根據(jù)原鏈表遍歷得到
        StudentLinkedList newList = new StudentLinkedList();
        StudentNode newHead = newList.getHead(); //新鏈表的頭節(jié)點(diǎn)
        //遍歷構(gòu)造
        boolean flag = true; //標(biāo)記是否為第一次添加
        while (old != null){
            //頭插法加入到新鏈表中
            StudentNode newNode = new StudentNode(old.no, old.name, old.age);
            if(flag){
                newHead.next = newNode;
                newNode.next = null;
                flag = false;
            }else {
                newNode.next = newHead.next;
                newHead.next = newNode;
            }
            old = old.next;
        }
        return newList;
    }

以上方式雖然可以實(shí)現(xiàn)鏈表的反轉(zhuǎn),但是是以返回一個(gè)新的反轉(zhuǎn)鏈表的形式,并沒有真正意義上實(shí)現(xiàn)原地反轉(zhuǎn),下面介紹另一種方式:

雙指針:

	/**
     * 雙指針就地反轉(zhuǎn)鏈表
     * @param head 接收鏈表的頭節(jié)點(diǎn),方法中會(huì)將鏈表反轉(zhuǎn)
     */
    public static void reverse(StudentNode head){
        //如果當(dāng)前鏈表為空 或者只有一個(gè)節(jié)點(diǎn) 直接返回即可
        if (head.next == null || head.next.next == null){
            return;
        }
        //輔助指針遍歷原來的鏈表
        StudentNode cur = head.next; //當(dāng)前節(jié)點(diǎn)
        StudentNode next = null; //指向cur的下一個(gè)節(jié)點(diǎn)
        StudentNode reverseHead = new StudentNode("", "", 0);
        //遍歷原來的鏈表,每遍歷一個(gè)節(jié)點(diǎn),就取出,放在新鏈表的最前端
        while (cur != null){
            next = cur.next; //暫時(shí)保存當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
            cur.next = reverseHead.next; //講cur下一個(gè)節(jié)點(diǎn)放在鏈表最前端
            reverseHead.next = cur;
            cur = next; //cur后移動(dòng)
        }
        head.next = reverseHead.next;
        return;
    }

2.4 百度–逆序打印單鏈表

從尾到頭打印單鏈表

方式一: 先將單鏈表反轉(zhuǎn),然后再打印。但是這樣會(huì)破壞掉原有單鏈表的結(jié)構(gòu),而題目要求僅僅是打印,因此不建議!

方式二: 利用棧模擬

將單鏈表的各個(gè)節(jié)點(diǎn)壓入棧中,利用棧先進(jìn)后出的特點(diǎn),實(shí)現(xiàn)逆序打印。

參考代碼:

    /**
     * 利用棧模擬 實(shí)現(xiàn)鏈表的逆序打印
     * @param head 鏈表的頭節(jié)點(diǎn)
     */
    public static void reversePrintList(StudentNode head){
        if (head.next == null){
            return; //空鏈表無法打印
        }
        //創(chuàng)建棧模擬逆序打印
        Stack<StudentNode> stack = new Stack<>(); //棧
        StudentNode cur = head.next;
        //將鏈表的所有節(jié)點(diǎn)壓入棧
        while (cur != null){
            stack.push(cur);
            cur = cur.next;
        }
        //逆序打印
        while (!stack.empty()){
            //出棧
            System.out.println(stack.pop());
        }
        return;
    }

以上就是Java數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)與面試題匯總的詳細(xì)內(nèi)容,更多關(guān)于Java單鏈表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java解析xml之dom解析xml示例分享

    java解析xml之dom解析xml示例分享

    DOM將整個(gè)XML文件加載到內(nèi)存中,并構(gòu)建出節(jié)點(diǎn)樹;應(yīng)用程序可以通過遍歷節(jié)點(diǎn)樹的方式來解析XML文件中的各個(gè)節(jié)點(diǎn)、屬性等信息; 這種方式便于對(duì)XML節(jié)點(diǎn)的添加修改等,而且解析也很方便,然后它比較耗費(fèi)內(nèi)存,解析速度也不快,下面看使用示例吧
    2014-01-01
  • 在Mybatis @Select注解中實(shí)現(xiàn)拼寫動(dòng)態(tài)sql

    在Mybatis @Select注解中實(shí)現(xiàn)拼寫動(dòng)態(tài)sql

    這篇文章主要介紹了在Mybatis @Select注解中實(shí)現(xiàn)拼寫動(dòng)態(tài)sql,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • RabbitMQ單機(jī)版部署安裝過程

    RabbitMQ單機(jī)版部署安裝過程

    RabbitMQ 是一個(gè)由 Erlang 語言開發(fā)的 AMQP 的開源實(shí)現(xiàn),在實(shí)現(xiàn)過程中需要注意由于rabbitmq是基于erlang語言開發(fā)的,所以必須先安裝erlang,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2022-03-03
  • MyBatis中一級(jí)緩存和二級(jí)緩存的區(qū)別

    MyBatis中一級(jí)緩存和二級(jí)緩存的區(qū)別

    MyBatis提供了兩級(jí)緩存機(jī)制,一級(jí)緩存和二級(jí)緩存,本文主要介紹了MyBatis中一級(jí)緩存和二級(jí)緩存的區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-07-07
  • Java如何把文件夾打成壓縮包并導(dǎo)出

    Java如何把文件夾打成壓縮包并導(dǎo)出

    這篇文章主要介紹了Java如何把文件夾打成壓縮包并導(dǎo)出,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出為Word文檔的方法步驟

    Java實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出為Word文檔的方法步驟

    我們在開發(fā)一些系統(tǒng)的時(shí)候,例如OA系統(tǒng),經(jīng)常能遇到將審批單數(shù)據(jù)導(dǎo)出為word和excel文檔的需求,導(dǎo)出為excel是比較簡單的,但是word文檔的格式不像表格那樣可以輕松的定位,所以本文給大家介紹了Java怎樣實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出為Word文檔,需要的朋友可以參考下
    2025-01-01
  • Spring注解之Service用法及示例詳解

    Spring注解之Service用法及示例詳解

    使用 @Service 注解可以將一個(gè)類聲明為業(yè)務(wù)邏輯組件,并將其對(duì)象存入 Spring 容器中,在控制器類中,通過注入該組件的實(shí)例,即可調(diào)用其中的方法,這篇文章主要介紹了Spring注解之Service用法及示例詳解,需要的朋友可以參考下
    2024-04-04
  • 詳解如何在Spring中為@Value注解設(shè)置默認(rèn)值

    詳解如何在Spring中為@Value注解設(shè)置默認(rèn)值

    在Spring開發(fā)中,我們經(jīng)常會(huì)遇到需要從配置文件中讀取屬性的情況,@Value注解是Spring提供的一種便捷方式,能夠讓我們輕松地將配置文件中的屬性注入到Spring Bean中,
    2024-10-10
  • SpringCloud開啟session共享并存儲(chǔ)到Redis的實(shí)現(xiàn)

    SpringCloud開啟session共享并存儲(chǔ)到Redis的實(shí)現(xiàn)

    這篇文章主要介紹了SpringCloud開啟session共享并存儲(chǔ)到Redis的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • JavaWeb實(shí)現(xiàn)Session跨頁面?zhèn)鬟f數(shù)據(jù)

    JavaWeb實(shí)現(xiàn)Session跨頁面?zhèn)鬟f數(shù)據(jù)

    本文主要介紹了 JavaWeb實(shí)現(xiàn)Session跨頁面?zhèn)鬟f數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07

最新評(píng)論

榆树市| 报价| 承德县| 南澳县| 乌兰察布市| 枞阳县| 灵山县| 禄丰县| 平顶山市| 诸城市| 佳木斯市| 河曲县| 资源县| 河南省| 三穗县| 庐江县| 昭觉县| 泰安市| 平利县| 绿春县| 建湖县| 赤城县| 闽清县| 镇巴县| 永靖县| 正蓝旗| 余干县| 栾川县| 清徐县| 克东县| 隆昌县| 鄢陵县| 灵石县| 汶川县| 县级市| 休宁县| 阿拉善左旗| 交城县| 香港 | 永清县| 乐平市|