溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用debug調(diào)試

發(fā)布時(shí)間:2021-10-18 15:24:58 來(lái)源:億速云 閱讀:127 作者:iii 欄目:編程語(yǔ)言

這篇文章主要講解了“如何使用debug調(diào)試”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何使用debug調(diào)試”吧!

一,反轉(zhuǎn)鏈表(經(jīng)典題目)

如何使用debug調(diào)試

1.1.1 題目分析

反轉(zhuǎn)鏈表是經(jīng)典的題目,題中信息描述很清晰,給定一個(gè)單鏈表,將其反轉(zhuǎn)。

先說(shuō)說(shuō)有什么思路呢?從題中給的案例輸出結(jié)果看,是不是只需要將輸入的鏈表的指針改成相反方向,就可以得到要輸出的結(jié)果。

就好比如下圖所示:

如何使用debug調(diào)試

但是問(wèn)題來(lái)了,我們是單鏈表,是沒(méi)辦法將下個(gè)節(jié)點(diǎn)直接指向該節(jié)點(diǎn)的上個(gè)節(jié)點(diǎn)。

因此就需要定義一個(gè)輔助指針,用來(lái)指向該節(jié)點(diǎn)的上個(gè)節(jié)點(diǎn),這樣就能完成,如下圖所示。

如何使用debug調(diào)試

那按照我們上面分析也就是將cur指針指向pre節(jié)點(diǎn)就可以了。

如何使用debug調(diào)試

注意:此處有坑

當(dāng)我們將當(dāng)前節(jié)點(diǎn)【cur】指向上一個(gè)節(jié)點(diǎn)【pre】的時(shí)候,如何將指針向下移動(dòng)呢?

此時(shí)的節(jié)點(diǎn)【cur】已經(jīng)指向了上一個(gè)節(jié)點(diǎn)【pre】了,所以我們還需要一個(gè)臨時(shí)變量去保存當(dāng)前節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn),具體為什么這么做,我們?cè)谙旅娲a演示的時(shí)候debug看下過(guò)程。

接著我們上面的步驟,將指針向下移動(dòng),如圖所示。

如何使用debug調(diào)試

移動(dòng)指針后,再將當(dāng)前節(jié)點(diǎn)的next指針指向上一個(gè)節(jié)點(diǎn)。

如何使用debug調(diào)試

最后當(dāng)前節(jié)點(diǎn)沒(méi)有下個(gè)節(jié)點(diǎn)的時(shí)候,就結(jié)束遍歷,如圖所示。

如何使用debug調(diào)試

1.1.2 代碼分析

按照套路,先初始化節(jié)點(diǎn)對(duì)象。

class ListNode {
    int val;
    ListNode next;
    ListNode() {
    }
    ListNode(int val) {
        this.val = val;
    }
    ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
    @Override
    public String toString() {
        return "ListNode{" +
                "val=" + val +
                '}';
    }
}

創(chuàng)建單鏈表結(jié)構(gòu)。

				// 創(chuàng)建單鏈表
        ListNode l1 = new ListNode(1);
        ListNode l2 = new ListNode(2);
        ListNode l3 = new ListNode(3);
        ListNode l4 = new ListNode(4);
        ListNode l5 = new ListNode(5);

        NodeFun nodeFun = new NodeFun();
        nodeFun.add(l1);
        nodeFun.add(l2);
        nodeFun.add(l3);
        nodeFun.add(l4);
        // 返回創(chuàng)建的鏈表
        ListNode node = nodeFun.add(l5);

反轉(zhuǎn)鏈表的代碼。

public ListNode reverseListIteration(ListNode head) {
        // 定義上節(jié)點(diǎn)輔助指針
        ListNode pre = null;
        // 定義當(dāng)前節(jié)點(diǎn)輔助指針
        ListNode cur = head;
        // 循環(huán)當(dāng)前節(jié)點(diǎn)不為空
        while (null != cur) {
            // 臨時(shí)變量保存當(dāng)前節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)
            ListNode temp = cur.next;
            // 當(dāng)前節(jié)點(diǎn)的next指向上節(jié)點(diǎn)
            cur.next = pre;
            // 上節(jié)點(diǎn)向下移動(dòng)
            pre = cur;
            // 當(dāng)前節(jié)點(diǎn)指向下個(gè)節(jié)點(diǎn)
            cur = cur.next;
        }
        return pre;
    }
1.1.3 debug調(diào)試

如何使用debug調(diào)試

節(jié)點(diǎn)初始化完成了,按照分析我們定義了2個(gè)節(jié)點(diǎn),如上圖第一次遍歷【pre】節(jié)點(diǎn)是null,【cur】從第一個(gè)節(jié)點(diǎn)開始。

下一步debug調(diào)試我們先不急,回顧之前說(shuō)的一個(gè)問(wèn)題,為什么要將當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)用臨時(shí)變量保存,那我們直接看debug調(diào)試。

如何使用debug調(diào)試

第一次遍歷的時(shí)候,修改完指針后當(dāng)前節(jié)點(diǎn)已經(jīng)指向上一個(gè)節(jié)點(diǎn)了,再看上述題目分析的圖解。

如何使用debug調(diào)試

這就是為啥要先把當(dāng)前節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)緩存起來(lái)。

如何使用debug調(diào)試 上圖debug我們看出,【cur】當(dāng)前節(jié)點(diǎn)的指針已經(jīng)指向null,下一步就是移動(dòng)指針指向下一個(gè)節(jié)點(diǎn)。

我們?cè)俳又M(jìn)行debug調(diào)試,按照上述分析,第二步循環(huán)就是將節(jié)點(diǎn)【2】指向上一個(gè)節(jié)點(diǎn)【1】,如下圖所示。

如何使用debug調(diào)試

現(xiàn)在當(dāng)前節(jié)點(diǎn)【cur】已經(jīng)指向【2】,那它的下個(gè)節(jié)點(diǎn)就是【1】,如下圖所示。

如何使用debug調(diào)試

經(jīng)過(guò)上面的兩步循環(huán),成功的將指針進(jìn)行了反轉(zhuǎn),剩下的節(jié)點(diǎn)循環(huán)也就如出一轍了。

如何使用debug調(diào)試

當(dāng)循環(huán)到最后節(jié)點(diǎn)【5】時(shí),下個(gè)節(jié)點(diǎn)為null,此時(shí)結(jié)束while循環(huán),而節(jié)點(diǎn)【5】也是指向了上一個(gè)節(jié)點(diǎn)【4】。

如何使用debug調(diào)試

最后我們?cè)倏聪逻\(yùn)行結(jié)果。

如何使用debug調(diào)試

二,回文鏈表

如何使用debug調(diào)試

1.2.1 題目分析

如果做過(guò)字符串的算法題,里面有個(gè)回文字符串的題目。沒(méi)錯(cuò),它倆的意思是一樣的。

看題目描述得知一個(gè)鏈表是不是回文鏈表,就是看鏈表就是看鏈表正讀和反讀是不是一樣的。

假如說(shuō),我們拿到了后半部分鏈表,再將其反轉(zhuǎn)。去和鏈表的前半部分比較,值相等就是回文鏈表了。

注意:

這種方式會(huì)破壞原鏈表的結(jié)構(gòu),為保證題目的一致性,最后再將鏈表再重新拼接

另外一種解題方式為:將整個(gè)鏈表節(jié)點(diǎn)遍歷保存到數(shù)組中,而數(shù)組是有下標(biāo),并可以直接獲取數(shù)組的大小,那么只需從數(shù)組的首尾去判斷即可

反轉(zhuǎn)鏈表上一道題我們已經(jīng)分享了,現(xiàn)在重點(diǎn)是如何獲取后半部分的鏈表。

我們?cè)僬f(shuō)說(shuō)快慢指針的思想,通常我們定義2個(gè)指針,一個(gè)移動(dòng)快,一個(gè)移動(dòng)慢。詳細(xì)的案例可以參考本人上一篇文章《開啟算法之路,還原題目,用debug調(diào)試搞懂每一道題》,有一道關(guān)于快慢指針的題目。

如何使用debug調(diào)試

定義慢指針每次移動(dòng)1個(gè)節(jié)點(diǎn),快指針每次移動(dòng)2個(gè)節(jié)點(diǎn),當(dāng)然我們是需要保證快節(jié)點(diǎn)的下下個(gè)個(gè)節(jié)點(diǎn)不為空。

slow = slow.next;
fast = fast.next.next;

如何使用debug調(diào)試

其實(shí)快慢指針的思想就是,假設(shè)鏈表是一個(gè)回文鏈表,快指針比慢指針是多走一步,當(dāng)快指針走完的時(shí)候,慢指針也就剛好走到該鏈表的一半。

上圖中slow指針正好走到鏈表的一半,此時(shí)也就得到鏈表的后半部分了,即slow.next。

1.2.2 代碼分析

老套路,先創(chuàng)建一個(gè)回文鏈表。

	ListNode l1 = new ListNode(1);
        ListNode l2 = new ListNode(2);
        ListNode l3 = new ListNode(2);
        ListNode l4 = new ListNode(1);
        
        NodeFun nodeFun = new NodeFun();
        nodeFun.add(l1);
        nodeFun.add(l2);
        nodeFun.add(l3);
        ListNode head = nodeFun.add(l4);

獲取后半部分鏈表代碼。

private ListNode endOfFirstHalf(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

反轉(zhuǎn)鏈表的代碼與上題目是一樣的。

最后將兩個(gè)鏈表進(jìn)行判斷是否是一樣的。

  			// 判斷是否回文
        ListNode p1 = head;
        ListNode p2 = secondHalfStart;
        boolean flag = true;
        while (flag && p2 != null) {
            if (p1.val != p2.val) {
                flag = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }
1.2.3 debug調(diào)試

先獲取鏈表的后半部分。

如何使用debug調(diào)試

如何使用debug調(diào)試 debug開始循環(huán)后,fast直接走到鏈表的第3個(gè)節(jié)點(diǎn)【2】

如何使用debug調(diào)試  slow.next就是鏈表的后半部分,再將后半部分進(jìn)行鏈表反轉(zhuǎn)

最后我們也就得到如下2個(gè)鏈表。

如何使用debug調(diào)試

最后將這2個(gè)鏈表進(jìn)行比較是否相等,相等則是回文鏈表。

三,鏈表的中間節(jié)點(diǎn)

如何使用debug調(diào)試

1.3.1 題目分析

獲取鏈表的中間節(jié)點(diǎn)乍一看和回文鏈表中使用快慢指針獲取后半鏈表有點(diǎn)類似呢?

如何使用debug調(diào)試

沒(méi)錯(cuò),這波操作是類似的,但也并不是完全一樣,其主要思想還是快慢指針。

換句話說(shuō),如果你已理解了上面的題,那這道題也就不是什么事了。話不多說(shuō),先來(lái)分析一波。

如何使用debug調(diào)試

同樣我們還是定義slow慢指針每次移動(dòng)一個(gè)節(jié)點(diǎn),fast快指針每次移動(dòng)2個(gè)節(jié)點(diǎn)。

如何使用debug調(diào)試

如何使用debug調(diào)試

那么fast快指針移動(dòng)到最后節(jié)點(diǎn)時(shí),slow慢指針也就是要返回的鏈表。

我想,你是不是有個(gè)疑問(wèn)。就是為什么慢指針是移動(dòng)一個(gè)節(jié)點(diǎn),快節(jié)點(diǎn)移動(dòng)2個(gè)節(jié)點(diǎn)?如果是偶數(shù)個(gè)節(jié)點(diǎn),這個(gè)規(guī)則還正確嗎!那就驗(yàn)證下。

為了方便,就繼續(xù)上面節(jié)點(diǎn)的遍歷。

如何使用debug調(diào)試

題目中描述,如果有2個(gè)中間節(jié)點(diǎn),返回第二個(gè)節(jié)點(diǎn),所以返回節(jié)點(diǎn)【4,5,6】也就符合要求了

1.3.2 代碼分析

創(chuàng)建鏈表結(jié)構(gòu)。

        ListNode l1 = new ListNode(1);
        ListNode l2 = new ListNode(2);
        ListNode l3 = new ListNode(3);
        ListNode l4 = new ListNode(4);
        ListNode l5 = new ListNode(5);

        NodeFun nodeFun = new NodeFun();
        nodeFun.add(l1);
        nodeFun.add(l2);
        nodeFun.add(l3);
        nodeFun.add(l4);
        ListNode head = nodeFun.add(l5);

獲取后半部分鏈表代碼。

	// 快慢指針
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            //移動(dòng)指針
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
1.3.3 debug調(diào)試

如何使用debug調(diào)試

快指針移動(dòng)到節(jié)點(diǎn)【3】,慢指針移動(dòng)到節(jié)點(diǎn)【2】

如何使用debug調(diào)試

接著再走一步,快指針移動(dòng)到節(jié)點(diǎn)【5】,慢節(jié)點(diǎn)移動(dòng)到節(jié)點(diǎn)【3】,到此也就滿足題意的要求了。

如何使用debug調(diào)試

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

如何使用debug調(diào)試

1.4.1 題目分析

這道題要求就是返回倒數(shù)K個(gè)節(jié)點(diǎn),最笨的辦法就是參考上面鏈表反轉(zhuǎn),先將鏈表反轉(zhuǎn)。獲取前K個(gè)節(jié)點(diǎn),將獲取的節(jié)點(diǎn)再次進(jìn)行反轉(zhuǎn)即可得到題目要求。

但是顯然這種方式只能滿足答案輸出,經(jīng)過(guò)上面的3道題目,有沒(méi)有得到什么啟發(fā)呢?

是的,這道題依然可以使用雙指針解決,是不是感覺(jué)雙指針可以解決所有的鏈表問(wèn)題了(QAQ)。

再仔細(xì)一想,是不是感覺(jué)和上一道《鏈表的中間節(jié)點(diǎn)》題目很類似?獲取鏈表的中間節(jié)點(diǎn)是返回后半部分節(jié)點(diǎn),而本道題是要求返回指定K個(gè)節(jié)點(diǎn)。

那就直接說(shuō)結(jié)論吧,同樣是定義快慢指針。只不過(guò)在上道題中快指針是每次移動(dòng)2個(gè)節(jié)點(diǎn),本道題中給定的K,就是快指針移動(dòng)的節(jié)點(diǎn)個(gè)數(shù)。

如何使用debug調(diào)試

同樣初始化指針都在首節(jié)點(diǎn),如果我們先將fast指針移動(dòng)K個(gè)節(jié)點(diǎn)。

如何使用debug調(diào)試

到此才算初始化節(jié)點(diǎn)完成,剩下的操作就是遍歷剩下的鏈表,直到fast指針指向最后一個(gè)節(jié)點(diǎn)。

如何使用debug調(diào)試

如何使用debug調(diào)試

如何使用debug調(diào)試

一直遍歷到fast節(jié)點(diǎn)為null,此時(shí)返回slow指針?biāo)敢墓?jié)點(diǎn)。

1.4.2 代碼分析

初始化鏈表,由于和前幾道題的操作是一樣的,此處就不在展示。

獲取倒數(shù)第K個(gè)節(jié)點(diǎn)的代碼。

public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode slow = head;
        ListNode fast = head;
        // 先將快指針向前移動(dòng)K
        while (k-- > 0) {
            fast = fast.next;
        }
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
1.4.3 debug調(diào)試

如何使用debug調(diào)試

按照上面圖解分析,fast快指針指向節(jié)點(diǎn)【3】的時(shí)候才算真正初始化快慢指針完成。

如何使用debug調(diào)試

當(dāng)快指針指向節(jié)點(diǎn)【5】時(shí),slow慢節(jié)點(diǎn)指向節(jié)點(diǎn)【3】

注意:中間省略了一步,即慢指針指向節(jié)點(diǎn)【2】時(shí),快指針指向節(jié)點(diǎn)【4】

節(jié)點(diǎn)【5】是最后一個(gè)節(jié)點(diǎn),再次進(jìn)入while循環(huán)。

如何使用debug調(diào)試

最后一次循環(huán)時(shí),慢指針指向了4,快指針下一個(gè)節(jié)點(diǎn)已經(jīng)為null,此時(shí)結(jié)束循環(huán)。

如何使用debug調(diào)試

五,移除重復(fù)節(jié)點(diǎn)

如何使用debug調(diào)試

1.5.1 題目分析

這道題和上一篇中的題目【刪除排序鏈表中的重復(fù)元素】是一樣的,簡(jiǎn)單的做法即利用Set集合保存未重復(fù)的節(jié)點(diǎn),再遍歷鏈表判斷是否已存在Set集合中。

因此本道題就不在多分析,直接貼上代碼。

1.5.2 代碼分析
Set<Integer> set = new HashSet<>();
        ListNode temp = head;
        while(temp != null && temp.next != null){
            set.add(temp.val);
            if(set.contains(temp.next.val)){
                temp.next = temp.next.next;
            }else{
                temp = temp.next;
            }
        }
        return head;
    }

感謝各位的閱讀,以上就是“如何使用debug調(diào)試”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何使用debug調(diào)試這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI