1. 程式人生 > >資料結構-棧&佇列&單向連結串列

資料結構-棧&佇列&單向連結串列

棧(Stack)是一種先進後出的資料結構。棧對於資料的操作只能從棧頂進行操作,新放入的資料都位於棧頂,也就是第一的位置,以前放入的就會被向下壓,所以資料入棧也叫做壓棧

棧
出棧的形式與入棧類似,每次都只能獲取棧頂的元素。如我們要取得“200”就必須先取出“300”,然後再取一次才能成功取得“200”.

public class Test01_Stack {
    public static void main(String[] args) {

        String[] data = {"a","b","c","d","e"};
        Stack<String> stack = new
Stack<String>(); for(String s:data){ stack.push(s);// 入棧的方法 } for(int i=0;i<data.length;i++){ String s = stack.pop();// 出棧的方法 System.out.println(s);// e d c b a }// Stack類還有其他三個常用操作方法,可以通過查詢API瞭解其使用方法 } }
  • 使用棧的先進後出特性實現快速排序的非遞迴演算法
public class Test03_quickSortNoRec {
    public static void main(String[] args) {
        int[] a = new int[20];
        Random random = new Random();
        for(int i=0;i<a.length;i++){
            a[i] = random.nextInt(101);
        }// 產生隨機陣列
        System.out.println(Arrays.toString(a));

        quickSort(a);// 排序
System.out.println(Arrays.toString(a)); } private static void quickSort(int[] a) { Stack<Node> stack = new Stack<>();// 建立棧物件 stack.push(new Node(0,a.length-1));// 壓棧,獲得第一次排序的邊界 while(!stack.empty()){// 當棧中空時,相當於所有的子遞迴全部實現 Node node = stack.pop();//出棧,取得當前排序的邊界,相當於一次遞迴 int left = node.left; int right = node.right; boolean isRight = false;// 快速排序演算法程式碼 // 降序排序 while(left < right){ if(a[left] < a[right]){ int t = a[left]; a[left] = a[right]; a[right] = t; isRight = !isRight; } if(isRight){ right--; }else{ left++; } } // 通過壓棧,實現類似遞迴的功能 if(right+1 < node.right){ stack.push(new Node(right+1,node.right)); } if(left-1 > node.left){ stack.push(new Node(node.left,left-1)); } } } } class Node{// 封裝類,儲存一次排序的左右邊界 public int left; public int right; public Node(int left, int right) { super(); this.left = left; this.right = right; } }

佇列

佇列是特殊的線性表,只允許在表的前端刪除元素,在表的後端插入元素。所以佇列是先進先出的資料結構。

  • 為什麼要使用佇列:
    • 計算機的任務排程系統
    • 為了削減高峰時期訂單請求,使用訊息佇列
    • 其它資料結構比如樹的廣度優先遍歷也需要藉助佇列來實現
    • Android中用於實現執行緒間通訊的訊息佇列是佇列的典型應用之一
// 自定義類實現佇列特性,在Java中,可以將LinkedList類用作佇列
public class MyQueue<E> {
    ArrayList<E> data = new ArrayList<E>();

    public void push(E value){
        data.add(value);
    }

    public E pop(){
        E pop = data.remove(0);
        return pop;
    }

    public boolean isEmpty(){
        return data.size()==0;
    }

    public E peek(){
        E peek = data.get(0);
        return peek;
    }

    public int size(){
        return data.size();
    }
}

連結串列(單向連結串列)

線性表是最基本、最簡單、也最常用的一種資料結構。線性表中資料元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素之外,其它資料元素都是首尾相接的。
一個連結串列是由節點組成的,類似於火車一樣。每個連結串列(火車)有n個節點(車廂),一個節點內(車廂內)一部分記憶體(空間)用來儲存資料值(乘客),還有一部分記憶體用來儲存指向下一個節點的地址(通向下一節車廂的門的鑰匙),我們通過訪問這個地址(鑰匙)就可以得到下一個節點(到達下一節車廂)。

// 自定義類實現連結串列的模擬
public class Test06_LinkedList {
    public static void main(String[] args) {
    // 一個MyNode物件就是一個節點
        MyNode<String> node = new MyNode<>("a");// 第一個節點
        MyNode<String> head = node;// 頭節點,火車頭

        // 第一個節點的next存放指向第二個節點的地址(鑰匙)
        node.next = new MyNode<>("b");
        // 通過鑰匙進入下一車廂
        node = node.next;
        // 第二個節點的next存放指向第三個節點的地址(鑰匙)
        node.next = new MyNode<>("c");

        node = node.next;

        // 回到頭節點
        node = head;
        // 遍歷連結串列
        while(node!=null){
            String str = node.value;// 取得節點儲存的資料值
            System.out.println(str);
            node = node.next;// 跳向下一個節點
        }
    }
}

節點類

public class MyNode<T> {
    public T value;// 節點中儲存的資料值
    public MyNode<T> next;// 節點中儲存的指向下一個節點的引用(鑰匙)
    public MyNode(T value) {
        super();
        this.value = value;
    }

    @Override
    public String toString() {
        return value.toString();
    }
}
  • 連結串列中刪除節點
public class Test07_LinkedList2 {
    public static void main(String[] args) {
        String[] data = {"a","b","c","d","e"};
        MyNode<String> node = new MyNode<String>(data[0]);
        MyNode<String> head = node;
        for(int i=1;i<data.length;i++){
            node.next = new MyNode<String>(data[i]);
            node = node.next;
        }

        Scanner scanner = new Scanner(System.in);
        int select;
        do{
            System.out.println("1-刪除首節點");
            System.out.println("2-刪除尾節點");
            System.out.println("3-刪除值為c的節點");
            System.out.println("4-退出");
            select = scanner.nextInt();
            switch(select){
            case 1:
                head = deleteFirstNode(head);// 刪除首節點
                myPrint(head);
                break;
            case 2:
                head = deleteLastNode(head);// 刪除尾節點
                myPrint(head);
                break;
            case 3:
                try {
                    head = deleteKeyNode(head,"e");// 刪除指定值的節點
                    myPrint(head);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            }
        }while(select!=4);// 退出條件

        scanner.close();
    }

    /**
     * 刪除指定值的節點
     * @param head
     * @throws Exception 
     */
    private static MyNode<String> deleteKeyNode(MyNode<String> head, String key) throws Exception {
        if(head == null){
            throw new Exception("連結串列不能為空");
        }
        if(head.value.equals(key)){// 刪除首節點的情況
            head = deleteFirstNode(head);
            return head;
        }

        MyNode<String> node = head.next;
        MyNode<String> preNode = head;

        while(node.next!=null){
            if(node.value.equals(key)){// 刪除中間節點的情況
                preNode.next = node.next;
                break;
            }
            preNode = node;
            node = node.next;
        }
        if(node.value.equals(key)){// 刪除尾節點的情況
            preNode.next = null;
            return head;
        }
        if(node.next==null){
            throw new Exception("刪除節點不存在");
        }
        return head;
    }

    /**
     * 遍歷連結串列,列印資訊
     * @param node
     */
    private static void myPrint(MyNode<String> node) {
        while(node!=null){
            System.out.println(node.value);
            node = node.next;
        }
    }

    /**
     * 刪除尾節點
     * @param head
     */
    private static MyNode<String> deleteLastNode(MyNode<String> head) {
        if(head==null || head.next==null){
            return null;
        }
        MyNode<String> result = head;
        while(head.next.next != null){
            head = head.next;
        }// 找到倒數第二個節點
        head.next = null;// 刪除最後一個節點
        return result;
    }

    /**
     * 刪除首節點
     * @param head
     * @return
     */
    private static MyNode<String> deleteFirstNode(MyNode<String> head) {
        if(head==null){
            return null;
        }
        head = head.next;
        return head;
    }
}

練習

2.合併兩個有序的連結串列,合併的連結串列仍然有序。
解題思路:
node1={1,3,5,7,9,12}
node2={2,4,6,8,10,11,13};
外迴圈遍歷node2連結串列
內迴圈遍歷node1連結串列,每次判斷node2是否能插入到node1連結串列中,
不能則node1遍歷至下一個節點。
能則退出內迴圈,將node2插入到node1連結串列中。
node2遍歷至下一個節點。

public class HomeWork01 {
    public static void main(String[] args) {
        int[] arr1 = {1,3,5,7,9,12};
        int[] arr2 = {2,4,6,8,10,11,13};
        MyNode<Integer> head1 = createLinkedList(arr1);// 建立第一個連結串列
        MyNode<Integer> head2 = createLinkedList(arr2);// 建立第二個連結串列

        merge(head1, head2);
        myPrint(head1);

    }

    /**
     * 合併連結串列
     * @param head1    被插入的目標連結串列
     * @param head2    用來插入的資料鏈表
     */
    private static void merge(MyNode<Integer> head1, MyNode<Integer> head2) {
        while(head2!=null){
            MyNode<Integer> node1=head1;// 獲得被插入連結串列的首節點
            int t = head2.value;// 獲得要插入的連結串列的對應節點資料
            MyNode<Integer> preNode=null;
            while(node1!=null){
                if(t <= node1.value){// 升序排序
                    break;
                }
                preNode = node1;
                node1=node1.next;
            }
            MyNode<Integer> insert = new MyNode<>(t);// 通過要插入的資料建立新的節點
            preNode.next = insert;// 將新的節點插入到目標連結串列中
            insert.next = node1;

            head2 = head2.next;// 遍歷資料鏈表,獲得下一個需要插入的值
        }
    }


    /**
     * 遍歷連結串列,列印資訊
     * @param head1
     */
    private static void myPrint(MyNode<Integer> head1) {
        MyNode<Integer> node = head1;
        while(node!=null){
            System.out.print(node.value + " ");
            node = node.next;
        }

    }

    /**
     * 建立連結串列
     * @param arr1
     * @return
     */
    private static MyNode<Integer> createLinkedList(int[] arr1) {
        MyNode<Integer> node = new MyNode<Integer>(arr1[0]);
        MyNode<Integer> head = node;
        for(int i=1;i<arr1.length;i++){
            node.next = new MyNode<Integer>(arr1[i]);
            node = node.next;
        }
        return head;
    }
}

相關推薦

資料結構-&佇列&單向連結串列

棧 棧(Stack)是一種先進後出的資料結構。棧對於資料的操作只能從棧頂進行操作,新放入的資料都位於棧頂,也就是第一的位置,以前放入的就會被向下壓,所以資料入棧也叫做壓棧。 出棧的形式與入棧類似,每次都只能獲取棧頂的元素。如我們要取得“200”就必須先取

資料結構線性表—單向連結串列

單向連結串列 其實就是一種鏈式儲存的資料結構,它和陣列不同,陣列的儲存結構就是連續的,且長度是固定的。而連結串列不一樣,它可以是連續的,也可以是不連續的,而且是可以動態擴容的。 連結串列中的資料是以節點的形式表現出來的。結構為:資料+指標 ┌───┬───┐ │data│next│ └

Algorithm——簡單資料結構佇列連結串列(十三)

Algorithm——簡單資料結構之佇列和連結串列佇列是一種先進先出策略,而連結串列中的各元素按線性順序排列。陣列的線性順序是由陣列的下標決定的,但連結串列的順序是由各個物件裡的指標決定的。佇列有入隊和出隊操作,連結串列則有插入、刪除、查詢表中節點的操作。佇列和雙向連結串列的

資料結構---自定義單向連結串列(Java實現)

單向連結串列是指每一個節點記憶體在一個指向下一個節點的指標,java中就是節點存在指向下一個節點的物件引用 下面是Node節點類 public class Node { private Object object; private Node next;

15 API-集合(Collection(功能,迭代器),List(List特有迭代器,併發異常),常見資料結構圖示(,佇列,陣列,連結串列))&物件陣列

1:物件陣列(掌握) (1)陣列既可以儲存基本資料型別,也可以儲存引用型別。它儲存引用型別的時候的陣列就叫物件陣列。 (2)案例:用陣列儲存5個學生物件,並遍歷陣列。 學生的物件 public class Student { // 成員變數 private Stri

資料結構】陣列、連結串列佇列、二叉樹

陣列 陣列儲存的資料在地址空間上是連續的。 方便資料的查詢,查詢資料的時間複雜度為O(1)。 連結串列 連結串列儲存的資料在地址空間上可連續,可不連續。 連結串列中的每一個節點都

重溫四大基礎資料結構:陣列、連結串列佇列

![file](https://img2020.cnblogs.com/other/1648938/202008/1648938-20200805081813714-1550683399.jpg) # 前言 > 本文收錄於專輯:[http://dwz.win/HjK](http://dwz.win/H

資料結構示例之用連結串列實現

以下是“使用連結串列實現棧”的簡單示例: 1. 用c語言實現的版本 #include<stdio.h> #include<stdlib.h> struct s_node { int data; struct s_node *next; };

資料結構】【多項式連結串列實現相加】

#include<bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1006; struct node { double coef; int exp; struct n

資料結構 筆記:迴圈連結串列的實現

什麼事迴圈連結串列? -概念上 ·任意資料元素都有一個前驅和一個後繼 ·所有的資料元素的關係構成一個邏輯上的環 -實現上 ·迴圈連結串列是一種特殊的單鏈表 ·尾結點的指標域儲存了首結點的地址 迴圈連結串列的實現思路 -通過模板定義CircleList類,繼承自L

資料結構之——陣列和連結串列

1. 陣列 1.1 陣列為什麼從零編號? 陣列名代表陣列的首地址,陣列的下標其實代表陣列中某個元素相對首地址的偏移量,陣列的第一個元素是零偏移,因此從 0 開始。 上面其實也只是一個解釋, C 語言設計者用零開始編號,後來的各種語言也便紛紛效仿,因此就形成了這個習慣。 1

《java常用演算法手冊》 第二章 資料結構 佇列

 順序棧的實現: package LineStructure; //參考 https://blog.csdn.net/icarus_wang/article/details/79561863 public cla

資料結構實驗三靜態連結串列學生資訊

#include<iostream>   #include<string>   using namespace std;      //靜態連結串列的儲存結構   c

資料結構:陣列和連結串列的區別以及各自的優缺點

原文地址 http://blog.csdn.net/qq_25806863/article/details/70607204 陣列和連結串列是兩種基本的資料結構,他們在記憶體儲存上的表現不一樣,所以也有各自的特點。 大致總結一下特點和區別,拿幾個人一起去看電影時坐座位為例。 陣列的特點

資料結構與演算法之連結串列篇(上)

連結串列作為一種基礎的資料結構之一,我們會常常使用到它,接下來就讓我們一起學習吧。 1、連結串列的經典應用場景: LRU快取淘汰演算法。 2、快取是一種提高資料讀取效能的技術,在硬體設計、軟體開發中都有著非常廣泛的應用,比如常見的CPU快取、資料庫快取、瀏覽器快取等等。

資料結構與演算法之連結串列篇(下)

Q:如何輕鬆寫出正確的連結串列程式碼? 總結起來,就是投入時間+技巧; 一、投入時間:          只要願意投入時間,大多數人都是可以學會的,比如說,如果你真能花上一個週末或者一整天時間,就去寫連結

Java資料結構(一)——連結串列

Java中的資料結構又很多種,如棧,佇列,樹等,但是他們的形式歸根到底就是兩種:一個是陣列,一個是連結串列,所有的結構都是對這兩個的變形。 什麼是線性表? 陣列和連結串列都屬於是線性表,那什麼是線性表:一個線性表是n個相同特性的資料元素的有序序列。各元素之間是一對一的關係。但這並不是

java版資料結構與演算法—有序連結串列

package com.zoujc.sortLink; /** * 有序連結串列 */ class Link { public int dData; public Link next; public Link(int dd){ dData = d

資料結構與演算法】連結串列——遞增排序

今天看書時偶然想到的問題,書上是要求將一個數據插入一個有序連結的線性連結串列中, 所以我想先進行連結串列內的資料排序在進行插入資料。 在這裡我只寫了排序的函式。   函式實現: void Sort(LinkList&list, int &n) {   f

自己動手實現java資料結構(二) 連結串列

1.連結串列介紹   前面我們已經介紹了向量,向量是基於陣列進行資料儲存的線性表。今天,要介紹的是線性表的另一種實現方式---連結串列。   連結串列和向量都是線性表,從使用者的角度上依然被視為一個線性的列表結構。但是,連結串列內部儲存資料的方式卻和向量大不相同:連結串列的核心是節點。節點儲存"資料"的同