国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > Java > 正文

面試題:用 Java 逆序打印鏈表

2024-07-14 08:41:27
字體:
供稿:網(wǎng)友

昨天的 Java 實現(xiàn)單例模式 中,我們的雙重檢驗鎖機(jī)制因為指令重排序問題而引入了 volatile 關(guān)鍵字,不少朋友問我,到底為啥要加 volatile 這個關(guān)鍵字呀,而它,到底又有什么神奇的作用呢?

對 volatile 這個關(guān)鍵字,在昨天的講解中我們簡單說了一下:被 volatile 修飾的共享變量,都會具有下面兩個屬性:

  • 保證不同線程對該變量操作的內(nèi)存可見性。
  • 禁止指令重排序。

共享變量:如果一個變量在多個線程的工作內(nèi)存中都存在副本,那么這個變量就是這幾個線程的共享變量。

可見性:一個線程對共享變量值的修改,能夠及時地被其它線程看到。

對于重排序,不熟悉的建議直接 Google 一下,這里也就不多提了。只需要記住,在多線程中操作一個共享變量的時候,一定要記住加上 volatile 修飾即可。

由于時間關(guān)系,我們還是得先進(jìn)入今天的正題,對于 volatile 關(guān)鍵字,在要求并發(fā)編程能力的面試中還是很容易考察到的,后面我也會簡單給大家講解。

輸入一個單鏈表的頭結(jié)點,從尾到頭打印出每個結(jié)點的值。

我們的鏈表有很多,單鏈表,雙向鏈表,環(huán)鏈表等。這里是最普通的單鏈表模式,我們一般會在數(shù)據(jù)存儲區(qū)域存放數(shù)據(jù),然后有一個指針指向下一個結(jié)點。雖然 Java 中沒有指針這個概念,但 Java 的引用恰如其分的填補(bǔ)了這個問題。

看到這道題,我們往往會很快反應(yīng)到每個結(jié)點都有 next 屬性,所以要從頭到尾輸出很簡單。于是我們自然而然就會想到先用一個 while 循環(huán)取出所有的結(jié)點存放到數(shù)組中,然后再通過逆序遍歷這個數(shù)組,即可實現(xiàn)逆序打印單鏈表的結(jié)點值。

我們假定結(jié)點的數(shù)據(jù)為 int 型的。實現(xiàn)代碼如下:

public class Test05 {  public static class Node {    int data;    Node next;  }  public static void printLinkReverse(Node head) {    ArrayList<Node> nodes = new ArrayList<>();    while (head != null) {      nodes.add(head);      head = head.next;    }    for (int i = nodes.size() - 1; i >= 0; i--) {      System.out.print(nodes.get(i).data + " ");    }  }  public static void main(String[] args) {    Node head = new Node();    head.data = 1;    head.next = new Node();    head.next.data = 2;    head.next.next = new Node();    head.next.next.data = 3;    head.next.next.next = new Node();    head.next.next.next.data = 4;    head.next.next.next.next = new Node();    head.next.next.next.next.data = 5;    printLinkReverse(head);  }}

這樣的方式確實能實現(xiàn)逆序打印鏈表的數(shù)據(jù),但明顯用了整整兩次循環(huán),時間復(fù)雜度為 O(n²)。等等!逆序輸出?似乎有這樣一個數(shù)據(jù)結(jié)構(gòu)可以完美解決這個問題,這個數(shù)據(jù)結(jié)構(gòu)就是棧。

棧是一種「后進(jìn)先出」的數(shù)據(jù)結(jié)構(gòu),用棧的原理更好能達(dá)到我們的要求,于是實現(xiàn)代碼如下:

public class Test05 {  public static class Node {    int data;    Node next;  }  public static void printLinkReverse(Node head) {    Stack<Node> stack = new Stack<>();    while (head != null) {      stack.push(head);      head = head.next;    }    while (!stack.isEmpty()) {      System.out.print(stack.pop().data + " ");    }  }  public static void main(String[] args) {    Node head = new Node();    head.data = 1;    head.next = new Node();    head.next.data = 2;    head.next.next = new Node();    head.next.next.data = 3;    head.next.next.next = new Node();    head.next.next.next.data = 4;    head.next.next.next.next = new Node();    head.next.next.next.next.data = 5;    printLinkReverse(head);  }}

既然可以用棧來實現(xiàn),我們也極容易想到遞歸也能解決這個問題,因為遞歸本質(zhì)上也就是一個棧結(jié)構(gòu)。要實現(xiàn)逆序輸出鏈表,我們每訪問一個結(jié)點的時候,我們先遞歸輸出它后面的結(jié)點,再輸出該結(jié)點本身,這樣鏈表的輸出結(jié)果自然也是反過來了。

代碼如下:

public class Test05 {  public static class Node {    int data;    Node next;  }  public static void printLinkReverse(Node head) {    if (head != null) {      printLinkReverse(head.next);      System.out.print(head.data+" ");    }  }  public static void main(String[] args) {    Node head = new Node();    head.data = 1;    head.next = new Node();    head.next.data = 2;    head.next.next = new Node();    head.next.next.data = 3;    head.next.next.next = new Node();    head.next.next.next.data = 4;    head.next.next.next.next = new Node();    head.next.next.next.next.data = 5;    printLinkReverse(head);  }}

雖然遞歸代碼看起來確實很整潔,但有個問題:當(dāng)鏈表非常長的時候,一定會導(dǎo)致函數(shù)調(diào)用的層級很深,從而有可能導(dǎo)致函數(shù)調(diào)用棧溢出。所以顯示用?;谘h(huán)實現(xiàn)的代碼,健壯性還是要好一些的。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 龙陵县| 阜宁县| 柘城县| 米林县| 开封市| 遵义县| 巴林左旗| 永登县| 公主岭市| 怀仁县| 阆中市| 鄂伦春自治旗| 从江县| 麻江县| 九江县| 湘西| 南投市| 六盘水市| 文成县| 广平县| 普宁市| 怀来县| 台北市| 龙南县| 融水| 德惠市| 洪湖市| 黄石市| 满洲里市| 瑞安市| 枣阳市| 志丹县| 沽源县| 隆德县| 潞城市| 麦盖提县| 万源市| 渭南市| 苏尼特左旗| 乌拉特后旗| 威宁|