Java實現單鍊表、棧、隊列三種數據結構

2021-03-02 Java專欄

注意文末有最新Java實戰項目面試題

作者:遠航

cnblogs.com/yang-guang-zhang/p/13884023.html

一、單鍊表

1、在我們數據結構中,單鍊表非常重要。它裡面的數據元素是以結點為單位,每個結點是由數據元素的數據和下一個結點的地址組成,在java集合框架裡面  LinkedList、HashMap(數組加鍊表)等等的底層都是用鍊表實現的。

2、下面是單鍊表的幾個特點:

數據元素在內存中存放的地址是不連續的:單鍊表的結點裡面還定義一個結點,它裡面保存著下一個結點的內存地址,在實例化對象的時候,jvm會開闢不同內存空間,並且是不連續的。

添加效率高:添加一個元素時,先找到插入位置的前一個,只需要將1,2個元素的連接斷開,將插入結點的next指向第一個元素的next

(1),然後將第一個元素的next指向插入結點(2),

不用在挪動後面元素。

刪除效率高:刪除一個元素時,先找到刪除位置,將前一個的next指向刪除位置的next,不用在挪動後面元素。


查詢效率低:查詢的時候必須從頭開始,依次遍歷,而數組因為它的內存是連續的,可以直接通過索引查找。

3、下面通過代碼來實現單鍊表結構:

package com.tlinkedList;

/**
* User:zhang
* Date:2020/10/26
**/
public class TLinkedList<T> {
  private Node head;//鍊表頭部
  private int size;//鍊表元素的個數
  public TLinkedList(){
      head=null;
      size=0;
  }
//    將結點作為內部類。也可以新建一個Node類,作為結點
  class Node{
      private Node next;//下一個結點
      private T t;//結點的數據
      public Node(T t){
          this.t=t;
      }

      public T getT() {
          return t;
      }

      public void setT(T t) {
          this.t = t;
      }
  }
//    在鍊表頭部添加一個結點
  public void addFirst(T t){
      Node node = new Node(t);
      node.next=head;
      head=node;
      size++;
  }
//    在鍊表中間添加一個結點
  public void addMid(T t,int index){
      Node node = new Node(t);
      Node mid=head;
      for (int i = 0; i < index - 1; i++) {
          mid=mid.next;
      }
      node.next=mid.next;
      mid.next=node;
      size++;
  }
//    在鍊表尾部添加一個結點
  public void addLast(T t){
      Node node = new Node(t);
      Node last=head;
      while (last.next!=null){
          last=last.next;
      }
      last.next=node;
      node.next=null;
      size++;
  }
//    刪除鍊表的頭結點
  public void removeFirst(){
      head=head.next;
      size--;
  }
//    刪除鍊表的中間元素
  public void removeMid(int index){
      Node mid=head;
      if (index==0){
          removeFirst();
          return;
      }
      int j=0;
      Node qMid=head;
      while (j<index){
          qMid=mid;
          mid=mid.next;
          j++;
      }
      qMid.next=mid.next;
      size--;
  }
//    刪除鍊表的尾結點
  public void removeLast(){
      Node mid=head;
      Node qMid=head;
      while (mid.next!=null){
           qMid=mid;
           mid=mid.next;
      }
      qMid.next= null;
      size--;
  }
//    獲取鍊表指定下標的結點
  public Node get(int index){
      Node mid=head;
      if (index==0){
          return head;
      }
      int j=0;
      while (j<index){
          mid=mid.next;
          j++;
      }
      return mid;
  }
  public static void main(String[] args) {
      TLinkedList<String> linkedList = new TLinkedList<>();
      linkedList.addFirst("hello1");
      linkedList.addFirst("hello2");
      linkedList.addFirst("hello3");
      for (int i = 0; i < linkedList.size; i++) {
          System.out.println(linkedList.get(i).getT());
      }
//        linkedList.removeLast();
//        linkedList.removeFirst();
//        linkedList.addLast("hello4");
      linkedList.addMid("hello",2);
      System.out.println("----");
      for (int i = 0; i < linkedList.size; i++) {
          System.out.println(linkedList.get(i).getT());
      }
  }
}

結果如下:

二、棧(Stack)

1、一提到棧我們腦海就會浮現四個字「先進後出」,沒錯,它就是棧的最大特點。


2、棧的應用場景也非常多,比如將字符串反轉、jvm裡面的棧區等等。

3、棧裡面的主要操作有:

peek(返回棧頂元素):將棧頂元素的數據返回
相當於只有一個開口就是尾部,只能從尾進,從尾出。

4、下面通過鍊表結構實現棧結構:

package com.tStack;


/**
* User:zhang
* Date:2020/10/26
**/
public class Test_Stack<T> {
  private Node head;//棧的頭結點
  private int size;//棧的元素個數
  class Node{
      private Node next;//下一個結點
      private T t;//結點的數據
      public Node(T t){
          this.t=t;
      }

      public T getT() {
          return t;
      }

      public void setT(T t) {
          this.t = t;
      }
  }

  public Test_Stack() {
      head=null;
      size=0;
  }

  public static void main(String[] args) {
      Test_Stack<String> TStack = new Test_Stack<>();
      TStack.push("hello1");
      TStack.push("hello2");
      TStack.push("hello3");
      for (int i = 0; i < 3; i++) {
          System.out.println(TStack.pop());
      }
  }
//    入棧
  public void push(T t){
      Node node = new Node(t);
      if (size==0){
          node.next=head;
          head=node;
          size++;
          return;
      }
      if (size==1){
          head.next=node;
          node.next=null;
          size++;
          return;
      }
      Node lastNode=head;
      while (lastNode.next!=null){
           lastNode=lastNode.next;
      }
      lastNode.next=node;
      node.next=null;
      size++;
  }
//    出棧
  public T pop(){
      if (size==0){
          System.out.println("棧內無值");
          return null;
      }
      if (size==1){
          T t = head.getT();
          head=null;
          size--;
          return t;
      }
      Node lastNode=head;
      Node qNode=head;
      while (lastNode.next!=null){
          qNode=lastNode;
          lastNode=lastNode.next;
      }
      T t = lastNode.getT();
      qNode.next=null;
      size--;
      return t;
  }
//    獲取棧裡面元素的個數
  public int getSize(){
      return size;
  }
//    返回棧頂元素
  public T peek(){
      if (size==0){
          System.out.println("棧內無值");
          return null;
      }
      if (size==1){
          return head.getT();
      }
      Node lastNode=head;
      while (lastNode.next!=null){
          lastNode=lastNode.next;
      }
      return lastNode.getT();
  }
}

結果:

三、隊列(Queue)

1、隊列的特點也用「先進先出」四個字來概括。就是先進去的元素先輸出出來。

2、我們常見的消息隊列就是隊列結構實現的。

3、隊列的常見操作如下:

pop(出隊):將頭結點的下一個結點作為頭,然後將原來的頭結點刪除。

4、通過鍊表結構實現隊列:

package com.tQueue;

/**
 * User:zhang
 * Date:2020/10/26
 **/
public class TQueue<T> {
    private Node front;//頭結點
    private Node tail;//尾結點
    private int size;//隊列中元素的個數
    class Node {
        private Node next;//下一個結點
        private T t;//結點的數據

        public Node(T t) {
            this.t = t;
        }

        public T getT() {
            return t;
        }

        public void setT(T t) {
            this.t = t;
        }
    }
    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public TQueue() {
        front = tail = null;
    }

    //    入隊
    public void put(T t) {
        Node node = new Node(t);
        if (size == 0) {
            front = tail = node;
            size++;
            return;
        }
        Node lastNode = front;
        while (lastNode.next != null) {
            lastNode = lastNode.next;
        }
        lastNode.next = node;
        tail = node;
        size++;
    }

    //    出隊
    public T pop() {
        if (size == 0) {
            System.out.println("隊列中無值");
            return null;
        }
        T t = front.getT();
        front=front.next;
        size--;
        return t;
    }

    public static void main(String[] args) {
        TQueue<String> tQueue = new TQueue<>();
        tQueue.put("Hello1");
        tQueue.put("Hello2");
        tQueue.put("Hello3");
        for (int i = 0; i < 3; i++) {
            System.out.println(tQueue.pop());
        }
    }
}

結果:

文章有不足之處,歡迎大家留言指正,謝謝大家啦!


---END---文末福利

相關焦點

  • 結合JAVA詳解鍊表、棧、隊列等數據結構
    排序、冒泡排序、二分法這些,都要涉及到時間複雜度、以及數據結構的知識,這門課,還是很重要的。為了啥其實數據結構,結構這個詞,就是將我們原本的一些數據,按照某種結構放到一起,為了更加便利以及後期對於這些數據的利用。不能胡來,亂放一遭,那樣整理起來很麻煩,並且不方便以後的二次利用。
  • 圖解堆算法、鍊表、棧與隊列
    在隊列中,調度程序反覆提取隊列中的第一個作業並運行,因為實際情況中某些時間較短的任務卻可能需要等待很長時間才能開始執行,或者某些不短小、但很重要的作業,同樣應當擁有優先權。而堆就是為了解決此類問題而設計的數據結構。
  • JS 數據結構與算法——棧 & 隊列
    寫在前面原計劃是把《你不知道的Javascript》三部全部看完的,偶然間朋友推薦了數據結構與算法的一套入門視頻,學之。發現數據結構並沒有想像中那麼遙不可及,反而發覺挺有意思的。手頭上恰好有《學習Javascript數據結構與算法》的書籍,便轉而先把數據結構與算法學習。一、認識數據結構什麼是數據結構?
  • Java線性數據結構之數組和鍊表篇
    按數據的邏輯結構來說,線性結構指N個元素數據的有序(次序)集合。Java程序中較為廣泛線性結構包含線性表,棧,隊列,雙隊列,數組等。今天詳細講解數組和鍊表結構。數組數組是指將相同的數據類型的元素按照一定順序進行排列的集合,是一塊連續的內存空間。優點:數據是連續的,且隨機訪問速度快,讀寫速度可用複雜度方程式表示為O(1);缺點:執行新增和刪除性能下降,可表示為O(N)。
  • Java 程式設計師必須掌握的 8 道數據結構面試題你會幾道?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫40多年後,這個等式仍被奉為真理。這就是為什麼在面試過程中,需要考察軟體工程師對數據結構的理解。幾乎所有的問題都需要面試者對數據結構有深刻的理解。
  • 用兩個棧實現隊列(劍指 Offer 題解Java版)
    用兩個棧實現隊列題目連結題目描述解題思路分析Java實現棧Java實現隊列分析棧的特點是先進後出,而隊列的特點是先進先出,主要就是在兩個棧中來回倒騰從而實現隊列的功能,就好像一個黑盒子,裡邊是兩個棧的操作,但其他人在用這個黑盒子的時候,感覺就像在用隊列一樣。隊列和棧只是邏輯性的數據結構,實現隊列和棧可以用數組實現,也可以用鍊表實現,只要滿足隊列先進先出,棧先進後出的特性就可以。
  • 數據結構中的鍊表,你知道多少?
    為什麼要講鍊表呢?這是因為java中有很多集合類底層都是通過鍊表來實現的。而且面試的時候,鍊表的實現是經常考的一個知識點。所以這篇文章的重點在於,如何使用代碼去實現這些數據結構。但是這篇文章我不打算直接上來就講鍊表,而是先從線性表開始。按照慣例先給出這篇文章的大致脈絡吧。
  • 黑馬程式設計師:程式設計師必學之數據結構介紹(第二部分)
    (用數組來實現這一結構)時間複雜度:存儲讀取:O(1)插入刪除:O(n)順序存儲結構的優缺點線性表的鏈式存儲結構:用任意一種存儲單元存儲數據元素,存儲單元可以是連續的也可以是不連續的。頭結點與頭指針異同4.2單鍊表:線性表的鏈式存儲結構,即單鍊表單鍊表時間複雜度:查找O(n)、插入O(n)[頭插法,尾插法]、刪除O(n)單鍊表結構和順序存儲結構對比:a、頻繁查找很少刪除和插入適用線性表的順序存儲結構(遊戲中人物信息[順序],人物裝備[鏈式]);b、線性表長度不確定情況下[鏈式]
  • 給Java程式設計師的20個鍊表面試題
    什麼是鍊表?數據結構在程序面試中極其重要。鍊表則是對數組數據結構進行的補充,是另一種常見的數據結構。和數組相似的是,鍊表也是線性數據結構,並以線性方式儲存元素。但是,和數組不同的是,鍊表不將元素儲存在連續的位置;相反,其元素分散在內存中的各個地方,並以節點進行相互連接。鍊表不過是一個節點的列表,其中每一個節點都包含存儲的值和下一個節點的位置。
  • 數據結構(Java版)教與學(48和60學時教學大綱)
    通過講授和上機實驗,使學生領會數據結構的基本原理,掌握線性表、棧和隊列、串、數組和稀疏矩陣、樹和二叉樹、圖、查找和排序等基本數據結構及其相關算法設計方法,具備數據組織、數據存儲和數據處理能力,利用數據結構方法求解實際問題的能力。
  • 《大話數據結構》pdf下載
    以一個計算機教師教學為場景,講解數據結構和相關算法的知識。通篇以一種趣味方式來敘述,大量引用了各種各樣的生活知識來類比,並充分運用圖形語言來體現抽象內容,對數據結構所涉及到的一些經典算法做到逐行分析、多算法比較。與市場上的同類數據結構圖書相比,本書內容趣味易讀,算法講解細緻深刻,是一本非常適合自學的讀物。本書以一個計算機教師教學為場景,講解數據結構和相關算法的知識。通篇?
  • 面試需要知道的六種數據結構
    本篇主講:數字、字符串;鍊表;棧;隊列;雙端隊列;樹。數組和字符串是最基本的數據結構,在很多程式語言中都有著十分相似的性質,而圍繞著它們的算法面試題也是最多的。棧是許多 LeetCode 中等難度偏上的題目裡面經常需要用到的數據結構。掌握好它是十分必要的。棧的最大特點就是後進先出(LIFO)。對於棧中的數據來說,所有操作都是在棧的頂部完成的,只可以查看棧頂部的數據,只能夠向棧的頂部壓入數據,也只能從棧的頂部彈出數據。
  • 順序棧與鏈式棧的圖解與實現
    # 順序棧與鏈式棧的圖解與實現棧是一種特殊的線性表,它與線性表的區別體現在增刪操作上棧的特點是先進後出,後進先出,也就是說棧的數據操作只能發生在末端,而不允許在中間節點進行操作如上圖所示,對棧的增刪操作都只能在末端也就是棧頂操作
  • Java數據結構和算法——圖
    1.2.2 鄰接矩陣的代碼實現public class Graph {private List vertexList;//存儲點的鍊表 private int[][] edges;//鄰接矩陣,用來存儲邊,值是權值 private int numOfEdges;//邊的數目 public Graph(int n) { //初始化矩陣,一維數組
  • 數據結構java面試題及答案
    6、用Java實現從一個給定數組中刪除重複元素?7、如何利用快速排序對一個整型數組進行排序?8、如何從一個數組中刪除重複元素?9、用Java實現數組反轉?10、如何不藉助庫實現從數組中刪除重複元素?鍊表問題鍊表是另外一個常見的數據結構,對數組結構是一個補充。
  • 一篇文章讓你了解二分搜索樹的數據結構的實現過程(Java 實現)
    樹結構簡介在線性數據結構中,數據都是排成一排存放的;而樹結構則是非線性的,存儲在其中的數據是按分支關係組織起來的結構,就像自然界中的樹那樣。而我們就可以針對各種特殊情況去設計出各情況適合的高效率的樹結構。舉個例子:比如對於查找一個數據,在線性結構中如果不知道具體位置的話需要在一堆數據裡一個一個地去尋找;而對於樹結構,因為樹結構分支的形式,各個數據可以存在不同的分支中,在查找時就可以依據這些分支快速地找到想要的數據。
  • 考研計算機重難點解析:數據結構
    針對這樣的情況,為我們的考生們精心準備了一些數據結構重難點解析和複習建議。統考大綱對數據結構的考查目標定位為掌握數據結構的基本概念、基本原理和基本方法,掌握數據的邏輯結構、存儲結構以及基本操作的實現;能夠對算法進行基本的時間複雜度和空間複雜度的分析;能夠運用數據結構的基本原理和方法進行問題的分析求解,具備採用C、C 或JAVA語言設計程序與實現算法的能力。
  • 深入分析java集合類LinkedList(源碼分析)
    一、LinkedList認識1、由鍊表認識LinkedList我們應該都學過數據結構與算法,如果你知道鍊表的實現原理,那麼你就可以直接看LinkedList的基本認識了,可以跳過本小節,如果你沒學過,或者是不牢固,那麼就先看看本小節再往下面學習吧。
  • 盤點數據結構的應用場景
    LRU 緩存淘汰算法鍊表是最基礎的數據結構,也是最常用的數據結構,很多複雜的數據結構都是通過鍊表演化而來的,而鍊表就可以用來實現LRU緩存淘汰。我們可以維護一個有序單鍊表,越靠近鍊表尾部的節點是越早之前訪問的。當有一個新的數據被訪問時,我們從鍊表頭部開始順序遍歷鍊表。
  • 應對程式設計師面試,你必須知道的八大數據結構
    棧、隊列等其他數據結構均由數組演變而來。下圖是一個包含元素(1,2,3和4)的簡單數組,數組長度為4。每個數據元素都關聯一個正數值,我們稱之為索引,它表明數組中每個元素所在的位置。大部分語言將初始索引定義為零。