面试中必知必会的那些题——单链表倒置
(準(zhǔn)備面試,多看點(diǎn)題。來自原文)
我想你去很多家公司面試的時(shí)候,遇到單鏈表倒置的問題可能比較多,如果一定要給面試題來一個(gè)排名,估計(jì)也能上top10吧,其實(shí)這個(gè)題目玩的是技巧和你對(duì)單鏈表的理解,其實(shí)我們仔細(xì)想想也不是很難,既然是倒置,那我們一定是一定要走一遍單鏈表的,對(duì)吧,那么走單鏈表有兩種形式,遞歸和循環(huán)兩種方式,而遞歸正是壓棧和出棧,那么我們就想起來了,這不就是順序和逆序的關(guān)系嗎?第二種就是循環(huán),還記得我們?cè)駥W(xué)習(xí)單鏈表的時(shí)候有一種插法叫做頭插法,這種插入復(fù)雜度為O(1),不好的地方就是順序插入的數(shù)字,出來的時(shí)候卻是反的,所以這個(gè)不就是可以將原先的鏈表原地倒置過來嗎?
一:遞歸
說到遞歸,我們腦子里面一定要有一個(gè)V型圖,還有一個(gè)就是好記性不如爛筆頭,算法這東西很難用腦子想的清楚的,多畫畫圖就見青天了,下面我就舉個(gè)簡(jiǎn)單的例子:現(xiàn)有鏈表L={8,1,6,3},需要將L倒置,然后我就畫好了V型圖。
從圖中可以看到,當(dāng)我遞歸到3再出棧的時(shí)候,只需要將6賦給3.next,1賦給6.next,然后這樣以此類推。。。最后結(jié)果就出來了,貌似口頭上描述起來很簡(jiǎn)單,但是在寫代碼的時(shí)候需要注意以下幾個(gè)點(diǎn),先上代碼說話。
public LinkNode Reverse(LinkNode node) {if (node.next == null)return node;var prevNode = Reverse(node.next);var temp = node.next;temp.next = node;node.next = null;return prevNode; }第一點(diǎn):我們?cè)谧哝湵淼臅r(shí)候,可以操控的只有兩個(gè)結(jié)點(diǎn),node和node.next,所以遞歸出口的時(shí)候,一定不能使用最常見的寫法。
if (node == null)return node;而應(yīng)該像下面這么寫,其實(shí)就告訴我們只需要走到6節(jié)點(diǎn)就行了,用6.next來判斷下是不是鏈尾,這樣做是方便我們進(jìn)行node和
node.next進(jìn)行節(jié)點(diǎn)交換。
if (node.next == null)return node;第二點(diǎn):當(dāng)我們每一次出棧的時(shí)候,其實(shí)也是退到曾今壓棧時(shí)的方法環(huán)境中,進(jìn)行節(jié)點(diǎn)交換的時(shí)候,也只能在當(dāng)前的方法上下文中起效,比如說:出棧到1的時(shí)候,其實(shí)3和6的節(jié)點(diǎn)已經(jīng)交換了,但是1這個(gè)方法環(huán)境不知道,它仍然指向6,但此時(shí)節(jié)點(diǎn)6.next再也不是3了,因?yàn)樵?和6進(jìn)行了交換,所以這不是我們所期望的,所以在回退的時(shí)候,一定要有一個(gè)鏈表保存這個(gè)所有節(jié)點(diǎn)交換的集合,恰巧在鏈表中有一個(gè)特征就是,只要我有一個(gè)指針始終指向頭結(jié)點(diǎn)的地址,它就相當(dāng)于一個(gè)集合的功能了,因?yàn)槲也还苣愫竺婀?jié)點(diǎn)怎么轉(zhuǎn)換,我都可以通過head.next依次找到后面痙攣的所有結(jié)點(diǎn),比如下圖中在出棧的過程中,每個(gè)出棧的方法環(huán)境中都依次交換了node和node.next結(jié)點(diǎn),而我的prevnode始終指向的是結(jié)點(diǎn)3,所以我通過3.next就可以找到后面所有的 變化,所以這里就是prevnode的精妙之處。
最后看一下倒置的輸出結(jié)果:
二:非遞歸實(shí)現(xiàn)
如果你知道頭插法,那么循環(huán)實(shí)現(xiàn)真的很簡(jiǎn)單,不像遞歸做法很難想到那個(gè)prevnode節(jié)點(diǎn),我們知道頭插法是把新節(jié)點(diǎn)插入到鏈表的頭部,而我們遍歷的時(shí)候又可以控制兩個(gè)節(jié)點(diǎn)node和node.next,所以依次采用頭插法,將node.next插入到node之前,有人說,那插入到node節(jié)點(diǎn)之前不就亂了嗎?所以在操作之前,我可以把node.next先保存起來,比如放到申請(qǐng)的一個(gè)叫next的節(jié)點(diǎn)上,為了保存新轉(zhuǎn)換的節(jié)點(diǎn),我們?cè)偕暾?qǐng)一個(gè)prev結(jié)點(diǎn)來保存頭插法中的新節(jié)點(diǎn)。
為了好理解,畫圖如下,其實(shí)這里要注意,結(jié)點(diǎn)還是那些結(jié)點(diǎn),并沒有刪除再添加。
public LinkNode Reserve(LinkNode node) {LinkNode prev = null;LinkNode next = null;while (node != null){next = node.next;node.next = prev;prev = node;node = next;}return prev; }
其實(shí)我們發(fā)現(xiàn),代碼只有那么一點(diǎn)點(diǎn),但是信息量還是蠻大的,這些東西要是用口頭描述還是很累的。
總結(jié)
以上是生活随笔為你收集整理的面试中必知必会的那些题——单链表倒置的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Amarino例程无法使用的问题
- 下一篇: 升级 ServeRADI-8i控制器,使