1. 程式人生 > >java資料結構與演算法之順序表與連結串列深入分析

java資料結構與演算法之順序表與連結串列深入分析

關聯文章:

  資料結構與演算法這門學科雖然在大學期間就已學習過了,但是到現在確實也忘了不少,因此最近又重新看了本書-《資料結構與演算法分析》加上之前看的《java資料結構》也算是對資料結構的進一步深入學習了,於是也就打算寫一系列的資料結構的博文以便加深理解,這些博文涵蓋了自己對資料結構與演算法的理解也包含了這類書籍的基礎內容,所以博文中會包含書中的一些概念的引用段落,看到時也不必驚訝,本篇是開篇,主要涵蓋順序表與連結串列的知識點,關於順序表與連結串列將會分兩篇博文記錄,而本篇將從以下幾點出發分析線性表的設計與實現。

1.線性表抽象資料型別概述

  首先來說明一下什麼是抽象資料型別,我們都知道java在預設情況下,所有的基本資料型別(int,float,boolean等)都支援基本運算,如加減法,這是因為系統已幫我們實現了這些基本資料型別的的基本運算。而對於自定義的資料型別(如類)也需要定義相應的運算,但在實際使用這些自定義的資料型別的運算時需要自己實現相關的運算,也就是說使用者自定義的資料型別的運算需要我們自己利用系統提供的基本運算來定義和實現。這些自定義了資料結構(如自定義類)和包含相關運算組合實現的資料型別就稱其為抽象資料型別(ADT,Abstract Data Type),因此一個ADT會包含資料宣告和運算宣告。常用的ADT包含連結串列、棧、佇列、優先佇列、二叉樹、散列表、圖等,所以接下來我們要分析的順序表和連結串列也屬於ADT範疇。下面引用自java資料結構一書對線性表的定義:

  線性表是由n(n>=0)個型別相同的資料元素a0,a1,…,an-1組成的有限的序列,在數學中記作(a0,a1,…,an-1),其中ai的資料型別可以是基本資料型別(int,float等)、字元或類。n代表線性表的元素個數,也稱其為長度(Length)。若n=0,則為空表;若n > 0,則ai(0 < i < n-1)有且僅有一個前驅(Predecessor)元素ai-1和一個後繼(Successor)元素ai+1,a0沒有前驅元素,ai沒有後繼元素。

以上便是對線性表抽象資料型別概述,下面我們開始分別針對順序表和連結串列進行深入分析。

2.線性表的順序儲存設計與實現(順序表)

2.1 順序儲存結構的設計原理概要

  順序儲存結構底層是利用陣列來實現的,而陣列可以儲存具有相同資料型別的元素集合,如int,float或者自定義型別等,當我們建立一個數組時,計算機作業系統會為該陣列分配一塊連續的記憶體塊,這也就意味著陣列中的每個儲存單元的地址都是連續的,因此只要知道了陣列的起始記憶體地址就可以通過簡單的乘法和加法計算出陣列中第n-1個儲存單元的記憶體地址,就如下圖所示:
這裡寫圖片描述
  通過上圖可以發現為了訪問一個數組元素,該元素的記憶體地址需要計算其距離陣列基地址的偏移量,即用一個乘法計算偏移量然後加上基地址,就可以獲得陣列中某個元素的記憶體地址。其中c代表的是元素資料型別的儲存空間大小,而序號則為陣列的下標索引。整個過程需要一次乘法和一次加法運算,因為這兩個操作的執行時間是常數時間,所以我們可以認為陣列訪問操作能再常數時間內完成,即時間複雜度為O(1),這種存取任何一個元素的時間複雜度為O(1)的資料結構稱之為隨機存取結構。而順序表的儲存原理正如上圖所示,因此順序表的定義如下(引用):

  線性表的順序儲存結構稱之為順序表(Sequential List),它使用一維陣列依次存放從a0到an-1的資料元素(a0,a1,…,an-1),將ai(0< i <> n-1)存放在陣列的第i個元素,使得ai與其前驅ai-1及後繼ai+1的儲存位置相鄰,因此資料元素在記憶體的物理儲存次序反映了線性表資料元素之間的邏輯次序。

2.2 順序儲存結構的實現分析

  接著我們來分析一下順序表的實現,先宣告一個順序表介面類ISeqList<T>,然後實現該介面並實現介面方法的程式碼,ISeqList介面程式碼如下:

package com.zejian.structures.LinkedList;

/**
 * Created by zejian on 2016/10/30.
 * 順序表頂級介面
 */
public interface ISeqList<T> {

    /**
     * 判斷連結串列是否為空
     * @return
     */
    boolean isEmpty();

    /**
     * 連結串列長度
     * @return
     */
    int length();

    /**
     * 獲取元素
     * @param index
     * @return
     */
    T get(int index);

    /**
     * 設定某個元素的值
     * @param index
     * @param data
     * @return
     */
    T set(int index, T data);

    /**
     * 根據index新增元素
     * @param index
     * @param data
     * @return
     */
    boolean add(int index, T data);

    /**
     * 新增元素
     * @param data
     * @return
     */
    boolean add(T data);

    /**
     * 根據index移除元素
     * @param index
     * @return
     */
    T remove(int index);

    /**
     * 根據data移除元素
     * @param data
     * @return
     */
    boolean remove(T data);

    /**
     * 根據data移除元素
     * @param data
     * @return
     */
    boolean removeAll(T data);

    /**
     * 清空連結串列
     */
    void clear();

    /**
     * 是否包含data元素
     * @param data
     * @return
     */
    boolean contains(T data);

    /**
     * 根據值查詢下標
     * @param data
     * @return
     */
    int indexOf(T data);

    /**
     * 根據data值查詢最後一個出現在順序表中的下標
     * @param data
     * @return
     */
    int lastIndexOf(T data);

    /**
     * 輸出格式
     * @return
     */
    String toString();
    }
}

  程式碼中聲明瞭一個Object陣列,初始化陣列大小預設為64,儲存的元素型別為泛型T,length則為順序表的長度,部分方法實現比較簡單,這裡不過多分析,我們主要分析get(int index)、set(int index, T data)、add(int index, T data)、remove(int index)、removeAll(T data)、indexof(T data)等方法的實現。

  • get(int index) 實現分析
    從順序表中獲取值是一種相當簡單的操作並且效率很高,這是由於順序表內部採用了陣列作為儲存資料的容器。因此只要根據傳遞的索引值,然後直接獲取陣列中相對應下標的值即可,程式碼實現如下:

    public T get(int index){
       if (index>=0 && index<this.length)
           return (T) this.table[index];         
       return null;
    }
  • set(int index, T data) 實現分析
    在順序表中替換值也是非常高效和簡單的,只要根據傳遞的索引值index找到需要替換的元素,然後把對應元素值替換成傳遞的data值即可,程式碼如下:

    public T set(int index, T data){
       if (index>=0 && index<this.length&& data!=null)
         {
             T old = (T)this.table[index];
             this.table[index] = data;
             return old;
         }
         return null;
     }
  • add(int index, T data)實現分析
    在順序表中執行插入操作時,如果其內部陣列的容量尚未達到最大值時,可以歸結為兩種情況,一種是在頭部插入或者中間插入,這種情況下需要移動陣列中的資料元素,效率較低,另一種是在尾部插入,無需移動陣列中的元素,效率高。但是當順序表內部陣列的容量已達到最大值無法插入時,則需要申請另一個更大容量的陣列並複製全部陣列元素到新的陣列,這樣的時間和空間開銷是比較大的,也就導致了效率更為糟糕了。因此在插入頻繁的場景下,順序表的插入操作並不是理想的選擇。下面是順序表在陣列容量充足下頭部或中間插入操作示意圖(尾部插入比較簡單就不演示了):
    這裡寫圖片描述
    順序表在陣列容量不充足的情況下頭部或中間插入操作示意圖:

    理解了以上幾種順序表的插入操作後,我們通過程式碼來實現這個插入操作如下,註釋很清晰就過多分析了:

    /**
       * 根據index插入元素
       * @param index 插入位置的下標,0作為起始值
       * @param data 插入的資料
       * @return
       */
      public boolean add(int index, T data){                                        
         if (data==null)
             return false;
    
         //插入下標的容錯判斷,插入在最前面
         if (index<0)                             
             index=0;
    
         //插入下標的容錯判斷,插入在最後面
         if (index>this.length)
             index = this.length;
    
         //判斷內部陣列是否已滿
         if (this.length==table.length)              
         {
             //把原陣列賦值給臨時陣列
             Object[] temp = this.table;
    
             //對原來的陣列進行成倍拓容,並把原陣列的元素複製到新陣列
             this.table = new Object[temp.length*2];   
    
             //先把原陣列下標從0到index-1(即插入位置的前一個位置)複製到新陣列
             for (int i=0; i<index; i++) {
                 this.table[i] = temp[i];
             }
         }
    
         //從原陣列的最後一個元素開始直到index位置,都往後一個位置
         // 最終騰出來的位置就是新插入元素的位置了
         for (int j=this.length-1; j>=index; j--) {
             this.table[j + 1] = this.table[j];
         }
         //插入新值
         this.table[index] = data;
         //長度加一
         this.length++;
         //插入成功
         return true;
      }
  • remove(int index) 實現分析
    順序表的刪除操作和前的插入操作情況是類似的,如果是在中間或者頭部刪除順序表中的元素,那麼在刪除位置之後的元素都必須依次往前移動,效率較低,如果是在順序表的尾部直接刪除的話,則無需移動元素,此情況下刪除效率高。如下圖所示在順序表中刪除元素ai時,ai之後的元素都依次往前移動:
    這裡寫圖片描述
    刪除操作的程式碼實現如下:

    /**
      * 根據index刪除元素
      * @param index 需要刪除元素的下標
      * @return
      */
     public T remove(int index)
     {
         if (this.length!=0 && index>=0 && index<this.length)
         {
             //記錄刪除元素的值並返回
             T old = (T)this.table[index];
    
             //從被刪除的元素位置開,其後的元素都依次往前移動
             for (int j=index; j<this.length-1; j++) {
                 this.table[j] = this.table[j + 1];
             }
             //設定陣列元素物件為空
             this.table[this.length-1]=null;
             //順序表長度減1
             this.length--;
             return old;                         
         }
         return null;
     }
  • removeAll(T data) 實現分析
    在順序表中根據資料data找到需要刪除的資料元素和前面分析的根據index刪除順序表中的資料元素是一樣的道理,因此我們只要通過比較找到與data相等的資料元素並獲取其下標,然後呼叫前面實現的remove(int index)方法來移除即可。程式碼實現如下:

    @Override
    public boolean removeAll(T data) {
        boolean done=false;
        if (this.length!=0 && data!=null)
        {
            int i=0;
            while (i<this.length)
                //找出資料相同的選項
                if (data.equals(this.table[i]))
                {
                    this.remove(i);//根據下標刪除
                    done = true;
                }
                else
                    i++;//繼續查詢
        }
        return done;
    }
  • indexOf(T data) 實現分析
    要根據data在順序表中查詢第一個出現的資料元素的下標,只需要通過對比資料項是否相等,相等則返回下標,不相等則返回-1,indexOf和lastIndexOf方法實現如下:

    /**
     * 根據資料查詢下標
     * @param data
     * @return
     */
    @Override
    public int indexOf(T data)
    {
        if (data!=null)
            for (int i=0; i<this.length; i++) {
                //相當則返回下標
                if (this.table[i].equals(data))
                    return i;
            }
        return -1;
    }
    
    /**
     * 根據data查詢最後一個出現在順序表中的下標
     * @param data
     * @return
     */
    @Override
    public int lastIndexOf(T data)
    {
        if (data!=null)
            for (int i=this.length-1; i>=0; i--)
                if (data.equals(this.table[i]))
                    return i;
        return -1;
    }

  以上便是順序表的主要的操作方法,當然順序表中還可以實現其他操作,如在初始化建構函式時傳入陣列來整體初始化順序表,比較兩個資訊表是否相等、是否包含某個資料等。這裡貼一下傳入資料構建順序表構造方法實現,其他實現程式碼我們這裡就不貼了,稍後實現原始碼都會上傳gitHub提供給大家:

/**
* 傳入一個數組初始化順序表
* @param array
*/
public SeqList(T[] array){
  if (array==null){
      throw new NullPointerException("array can\'t be empty!");
  }
  //建立對應容量的陣列
  this.table = new Object[array.length];
//複製元素
  for (int i=0;i<array.length;i++){
      this.table[i]=array[i];
  }

  this.length=array.length;
}

2.3 順序儲存結構的效率分析

  通過上述的分析,我們對順序表的實現已有了比較清晰的認識,接下來看一下順序表的執行效率問題,主要針對獲取、插入、修改、刪除等主要操作。前面分析過,由於順序表內部採用了陣列作為儲存容器,而陣列又是隨機存取結構的容器,也就是說在建立陣列時作業系統給陣列分配的是一塊連續的記憶體空間,陣列中每個儲存單元的地址都是連續的,所以在知道陣列基地址後可以通過一個簡單的乘法和加法運算即可計算出其他儲存單元的記憶體地址(實際上計算機內部也就是這麼做的),這兩個運算的執行時間是常數時間,因此可以認為陣列的訪問操作能在常數時間內完成,即順序表的訪問操作(獲取和修改元素值)的時間複雜為O(1)。
  對於在順序表中插入或者刪除元素,從效率上則顯得不太理想了,由於插入或者刪除操作是基於位置的,需要移動陣列中的其他元素,所以順序表的插入或刪除操作,演算法所花費的時間主要是用於移動元素,如在順序表頭部插入或刪除時,效率就顯得相當糟糕了。若在最前插入或刪除,則需要移動n(這裡假設長度為n)個元素;若在最後插入或刪除,則需要移動的元素為0。這裡我們假設插入或刪除值為第i(0<i<=n)個元素,其概率為pi,則插入或刪除一個元素的平均移動次數求和為:

p1(n1)+p2(n2)+...+pi(ni)+...+pn11+pn0=i=1n(pi(ni))

如果在各個位置插入元素的概率相同即 pi=1n+1 (n+1個插入位置任意選擇一個的概率)則有:

i=1n(pi(ni))=1n+1i=1n(ni)=1n+1n(n+1)2=n2=O(n)

  也就是說,在等概率的情況下,插入或者刪除一個順序表的元素平均需要移動順序表元素總量的一半,其時間複雜度是O(n)。當然如果在插入時,內部陣列容量不足時,也會造成其他開銷,如複製元素的時間開銷和新建陣列的空間開銷。
  因此總得來說順序表有以下優缺點:

  • 優點

    • 使用陣列作為內部容器簡單且易用

    • 在訪問元素方面效率高

    • 陣列具有記憶體空間區域性性的特點,由於本身定義為連續的記憶體塊,所以任何元素與其相鄰的元素在實體地址上也是相鄰的。

  • 缺點

    • 內部陣列大小是靜態的,在使用前必須指定大小,如果遇到容量不足時,需動態拓展內部陣列的大小,會造成額外的時間和空間開銷

    • 在內部建立陣列時提供的是一塊連續的空間塊,當規模較大時可能會無法分配陣列所需要的記憶體空間

    • 順序表的插入和刪除是基於位置的操作,如果需要在陣列中的指定位置插入或者刪除元素,可能需要移動內部陣列中的其他元素,這樣會造成較大的時間開銷,時間複雜度為O(n)

3.線性表的鏈式儲存設計與實現(連結串列)

3.1 連結串列的鏈式儲存結構設計原理概要

  通過前面對線性順序表的分析,我們知道當建立順序表時必須分配一塊連續的記憶體儲存空間,而當順序表內部陣列的容量不足時,則必須建立一個新的陣列,然後把原陣列的的元素複製到新的陣列中,這將浪費大量的時間。而在插入或刪除元素時,可能需要移動陣列中的元素,這也將消耗一定的時間。鑑於這種種原因,於是連結串列就出場了,連結串列在初始化時僅需要分配一個元素的儲存空間,並且插入和刪除新的元素也相當便捷,同時連結串列在記憶體分配上可以是不連續的記憶體,也不需要做任何記憶體複製和重新分配的操作,由此看來順序表的缺點在連結串列中都變成了優勢,實際上也是如此,當然連結串列也有缺點,主要是在訪問單個元素的時間開銷上,這個問題留著後面分析,我們先通過一張圖來初步認識一下連結串列的儲存結構,如下:

  從圖可以看出線性連結串列的儲存結構是用若干個地址分散的儲存單元存放資料元素的,邏輯上相鄰的資料元素在物理位置上不一定相鄰,因此每個儲存單元中都會有一個地址指向域,這個地址指向域指明其後繼元素的位置。在連結串列中儲存資料的單元稱為結點(Node),從圖中可以看出一個結點至少包含了資料域和地址域,其中資料域用於儲存資料,而地址域用於儲存前驅或後繼元素的地址。前面我們說過連結串列的插入和刪除都相當便捷,這是由於連結串列中的結點的儲存空間是在插入或者刪除過程中動態申請和釋放的,不需要預先給單鏈表分配儲存空間的,從而避免了順序表因儲存空間不足需要擴充空間和複製元素的過程,提高了執行效率和儲存空間的利用率。

3.2 單鏈表的儲結構實現分析

到此我們已初步瞭解了連結串列的概念和儲存結構,接下來,開始分析連結串列的實現,這裡先從單鏈表入手。同樣地,先來定義一個頂級的連結串列介面:ILinkedList和儲存資料的結點類Node,該類是代表一個最基本的儲存單元,Node程式碼如下:

/**
 * Created by zejian on 2016/10/21.
 * 單向連結串列節點
 */
public class Node<T> {
    public T data;//資料域
    public Node<T> next;//地址域

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

    public Node(T data,Node<T> next){
        this.data=data;
        this.next=next;
    }
}

接著頂級的連結串列介面ILinkedList,該介面聲明瞭我們所有需要實現的方法。

/**
 * Created by zejian on 2016/10/21.
 * 連結串列頂級介面
 */
public interface ILinkedList<T> {
    /**
     * 判斷連結串列是否為空
     * @return
     */
    boolean isEmpty();

    /**
     * 連結串列長度
     * @return
     */
    int length();

    /**
     * 獲取元素
     * @param index
     * @return
     */
    T get(int index);

    /**
     * 設定某個結點的的值
     * @param index
     * @param data
     * @return
     */
    T set(int index, T data);

    /**
     * 根據index新增結點
     * @param index
     * @param data
     * @return
     */
    boolean add(int index, T data);

    /**
     * 新增結點
     * @param data
     * @return
     */
    boolean add(T data);

    /**
     * 根據index移除結點
     * @param index
     * @return
     */
    T remove(int index);

    /**
     * 根據data移除結點
     * @param data
     * @return
     */
    boolean removeAll(T data);

    /**
     * 清空連結串列
     */
    void clear();

    /**
     * 是否包含data結點
     * @param data
     * @return
     */
    boolean contains(T data);

      /**
     * 輸出格式
     * @return
     */
    String toString();
}

建立一個單鏈表SingleILinkedList並實現ILinkedList介面,覆蓋其所有方法,宣告一個單鏈表的頭結點head,代表連結串列的開始位置,如下:

public class SingleILinkedList<T> implements ILinkedList<T> {
   protected Node<T> headNode; //帶資料頭結點

   public SingleILinkedList(Node<T> head) {
       this.headNode = head;
   }
   //其他程式碼先省略
   .....
}
  • boolean isEmpty()實現分析
    需要判斷連結串列是否為空的依據是頭結點head是否為null,當head=null時連結串列即為空連結串列,因此我們只需判斷頭結點是否為空即可,isEmpty方法實現如下:

    /**
     * 判斷連結串列是否為空
     * @return
     */
    @Override
    public boolean isEmpty() {
        return this.head==null;
    }
  • int length()實現分析
    由於單鏈表的結點數就是其長度,因此我們只要遍歷整個連結串列並獲取結點的數量即可獲取到連結串列的長度。遍歷連結串列需要從頭結點HeadNode開始,為了不改變頭結點的儲存單元,宣告變數p指向當前頭結點和區域性變數length,然後p從頭結點開始訪問,沿著next地址鏈到達後繼結點,逐個訪問,直到最後一個結點,每經過一個結點length就加一,最後length的大小就是連結串列的大小。實現程式碼如下:

    @Override
    public int length() {
       int length=0;//標記長度的變數
       Node<T> p=head;//變數p指向頭結點
       while (p!=null){
           length++;
           p=p.next;//後繼結點賦值給p,繼續訪問
       }
       return length;
    }
  • T get(int index)實現分析
    在單鏈表中獲取某個元素的值是一種比較費時間的操作,需要從頭結點開始遍歷直至傳入值index指向的位置,其中需要注意的是index是從0開始計算,也就是說傳遞的index=3時,查詢的是連結串列中第4個位置的值。其查詢獲取值的過程如下圖所示:
    這裡寫圖片描述
    程式碼實現如下:

    /**
     * 根據index索引獲取值
     * @param index 下標值起始值為0
     * @return
     */
    @Override
    public T get(int index) {
    
        if(this.head!=null&&index>=0){
            int count=0;
            Node<T> p=this.head;
            //找到對應索引的結點
            while (p!=null&&count<index){
                p=p.next;
                count++;
            }
    
            if(p!=null){
                return p.data;
            }
        }
        return null;
    }

    通過上圖和程式碼,我們就可以很容易理解連結串列中取值操作的整個過程了。

  • T set(int index, T data)實現分析
    根據傳遞的index查詢某個值並替換其值為data,其實現過程的原理跟get(int index)是基本一樣的,先找到對應值所在的位置然後刪除即可,不清晰可以看看前面的get方法的圖解,這裡直接給出程式碼實現:

    /**
     * 根據索引替換對應結點的data
     * @param index 下標從0開始
     * @param data
     * @return 返回舊值
     */
    @Override
    public T set(int index, T data) {
    
        if(this.head!=null&&index>=0&&data!=null){
            Node<T> pre=this.head;
            int count=0;
            //查詢需要替換的結點
            while (pre!=null&&count<index){
                pre=pre.next;
                count++;
            }
            //不為空直接替換
            if (pre!=null){
                T oldData=pre.data;
                pre.data=data;//設定新值
                return oldData;
            }
    
        }
        return null;
    }
  • add(int index, T data)實現分析
    單鏈表的插入操作分四種情況:
    a.空表插入一個新結點,插語句如下:

    head=new Node<T>(x,null);

    這裡寫圖片描述

    b.在連結串列的表頭插入一個新結點(即連結串列的開始處),此時表頭head!=null,因此head後繼指標next應該指向新插入結點p,而p的後繼指標應該指向head原來的結點,程式碼如下:

    //建立新結點
    Node<T> p =new Node<T>(x,null);
    //p的後繼指標指向head原來的結點
    p.next=head;
    //更新head
    head=p;

    以上程式碼可以合併為如下程式碼:

    //建立新結點,其後繼為head原來的結點,head的新指向為新結點
    head=new Node<T>(x,head);

    執行過程如下圖:

    相關推薦

    java資料結構演算法順序連結串列深入分析

    關聯文章:   資料結構與演算法這門學科雖然在大學期間就已學習過了,但是到現在確實也忘了不少,因此最近又重新看了本書-《資料結構與演算法分析》加上之前看的《java資料結構》也算是對資料結構的進一步深入學習了,於是也就打算寫一系列的資料結構的博文以便加

    資料結構-第一章,順序連結串列,棧結構,佇列結構的關係(個人見解)

    首先 順序表  和 連結串列是 兩個儲存結構。分別有自己的儲存特點。 其次 順序表 和 連結串列分別存放在不同的地方,“這個地方”就是 “棧” 或者 “佇列” 了 其實就是按照   FIFO先進先出 和  FILO先進後出 來處理資料所區別。 {{{而對於 FIFO 呢

    資料結構演算法順序C語言實現

    順序表等相關概念請自行查閱資料,這裡主要是實現。 注: 1.順序表C語言實現; 2.按較簡單的方式實現,主要幫助理解,可在此基礎上修改,更加完善; 3.提供幾個簡單函式,可自行新增功能; 4.可用C++封裝,得知STL中vector原理。    順序表容量。 #def

    Java資料結構演算法--雜湊

    Hash表也稱散列表,直譯為雜湊表,hash表是一種根據關鍵字值(key-value)而直接進行訪問的資料結構。它基於陣列,通過把關鍵字對映到陣列的某個下標來加快查詢速度,這種對映轉換作用的函式我們稱之為雜湊函式。 每種雜湊表都有自己的雜湊函式,雜湊函式是自己定義的,沒有統一的標準,下面我們

    資料結構設計作業順序考生系統

    #include<iostream> #include<stdio.h> #include<conio.h> #include<stdlib.h> #include<string.h> using namespace

    java資料結構(一)----------順序操作例項

    import java.util.Scanner; class DATA{//資料類 String key; // 節點的關鍵字 String name; String age; } class SLType{// 定義順序表的結構陣列 static fina

    java資料結構演算法(雜湊)

    什麼是雜湊表? 雜湊表是一種資料結構,提供快速的插入和查詢操作。 優點: 插入、查詢、刪除的時間級為O(1); 資料項佔雜湊表長的一半,或者三分之二時,雜湊表的效能最好。缺點: 基於陣列,陣列建立後難於擴充套件,某些雜湊表被基本填滿時效能下降的非常嚴重;沒有一種簡單的方

    資料結構那點事--線性連結串列

    #include<iostream> #include<stdlib.h> using namespace std; //鏈式線性表的儲存結構 #define OK 1 #define ERROR 0 #define TRUE 1 #de

    Java資料結構--集合、陣列、佇列、連結串列

    一、集合 1、集合型別主要有3種:list、set和Map. 2、集合介面分為:Collection和Map,list、set實現了Collection介面.他的一個類繼承結構如下: Collection<--List<--Vector Collectio

    資料結構演算法線性簡單定義(順序結構儲存查,增,刪)

    線性表(List) 由零個或多個數據元素組成的有限序列,它是一個序列,也就是說元素之間是有個先來後到的,若元素存在多個,則第一個元素無前驅,最後一個元素無後繼,其他元素有且只有一個前驅和後繼,另外,線性表強調是有限的,事實上無論計算機發展多強大,它處理的元素都是有限的。

    資料結構(一)順序連結串列

    順序表 運用陣列結構來構建的線性表就是順序表。 本例實現了順序表的列印、清空、判斷是否為空、求表長、獲得指定下標的元素、獲得指定元素的下標、插入和刪除操作。 #include<iostream> const int MAXSIZE=100; using

    Java資料結構演算法(一)線性結構單鏈

    Java資料結構和演算法(一)線性結構之單鏈表 prev current next -------------- -------------- -------------- | value | next | ->

    資料結構演算法線性相關程式

    1.從有序表中刪除所有值重複的元素,使所有值均不同 #include<stdio.h> #define MaxSize 50 #define Elemtype int typedef struct{ Elemtype data[MaxSize]; int

    資料結構演算法美專欄學習筆記-複雜度分析

    複雜度分析 什麼是複雜度分析 資料結構和演算法解決是“如何讓計算機更快時間、更省空間的解決問題”。 因此需從執行時間和佔用空間兩個維度來評估資料結構和演算法的效能。 分別用時間複雜度和空間複雜度兩個概念來描述效能問題,二者統稱為複雜度。 複雜度描述的是演算法執行時間(或佔用空間)與資料規模的增長關係

    資料結構演算法美 課程筆記二 複雜度分析(上)

    資料結構和演算法本身解決的是“快”和“省”的問題,即如何讓程式碼執行得更快,如何讓程式碼更省空間。所以,執行效率是演算法一個非常重要的考量指標。衡量演算法的執行效率最常用的就是時間和空間複雜度分析。 一、為什麼需要複雜度分析? 把程式碼跑一遍,通過統計、監控來得到演算法執行的時間和佔用的記憶

    Java資料結構演算法(三)順序儲存的樹結構

    Java資料結構和演算法(三)順序儲存的樹結構 二叉樹也可以用陣列儲存,可以和完全二叉樹的節點一一對應。 一、樹的遍歷 // 二叉樹儲存在陣列中 int[] data; public void preOrder() { preOrder(0); } // 前序遍歷指定的節點 public

    資料結構 2-11設順序va中的資料元素遞增有序。試寫一演算法,將x插入到順序的適當位置上,以保持該的有序性。

    將近半年時間內一直沒有寫部落格了,最近一直研究資料結構。該是整理一下的時候了。採用的是嚴蔚敏的習題集。 2.11設順序表va中的資料元素遞增有序。試寫一演算法,將x插入到順序表的適當位置上,以保持該表的有序性。 演算法思想: 1 3 4 5 6 7 8 9 假如插入的是2則,需要將所有比2大的

    Java資料結構演算法:HashMap,雜湊,雜湊函式

    1. HashMap概述 HashMap是基於雜湊表的Map介面的非同步實現(Hashtable跟HashMap很像,唯一的區別是Hashtalbe中的方法是執行緒安全的,也就是同步的)。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保

    資料結構的基本概念 順序連結串列的區別

     1.資料:就是符號  輸入到計算機被計算機加工處理的符號的集合   特點:輸入到計算機  可以被計算機加工處理  2.資料結構把資料分為:數值型別和非數值型別   3.資料元素:組成資料基本元素  

    資料結構2-動態生成順序的例項分析

    動態建立一個順序表,並完成插入和刪除的操作。程式碼如下: #include"stdio.h" #include"conio.h" #define MaxSize 10 typedef int ElemType;/*將int定義為ElemType*/ typedef str