<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【久遠(yuǎn)講算法3】數(shù)組——最簡單的數(shù)據(jù)結(jié)構(gòu)

          共 4349字,需瀏覽 9分鐘

           ·

          2021-10-27 07:10

          閱讀本文大概需要6分鐘

          你好,我是久遠(yuǎn),前面兩篇文章:

          我們對算法以及時空復(fù)雜度進(jìn)行了詳細(xì)的講解,但是,這其實是遠(yuǎn)遠(yuǎn)不夠的,時空復(fù)雜度只是我們算法學(xué)習(xí)中的冰山一角,下面讓我們通過數(shù)組的學(xué)習(xí)來正式打開算法與數(shù)據(jù)結(jié)構(gòu)的大門吧!


          以下是我之后文章的具體走向,感興趣的小伙伴可以跟著路線進(jìn)行自學(xué)哦!

          基礎(chǔ)篇暫定走向為:數(shù)組→鏈表→棧和隊列→樹→遞歸

          基礎(chǔ)篇更完以后我將會開啟力扣刷題套路篇哦,帶大家一起提高對編程語言以及算法的熟練度。


          什么是數(shù)組


          關(guān)于數(shù)組,雖然它是數(shù)據(jù)結(jié)構(gòu)世界里最常用以及最簡單的,但是之前仍有同學(xué)向我反饋:數(shù)組難以理解!那我們就來對數(shù)組進(jìn)行詳細(xì)的講解,幫助大家解惑。


          首先我們在此聲明,python 本身的庫中其實是沒有數(shù)組這個內(nèi)置類型的,但存在有列表 ( list )這個內(nèi)置類型,列表和數(shù)組在長相以及實際應(yīng)用上是相似的,因此我嘗試拿列表來進(jìn)行數(shù)組相關(guān)知識的講解。(實際上在 python 的 numpy 庫中是存在有數(shù)組這樣一個數(shù)據(jù)結(jié)構(gòu)的,之后我們會專門寫一篇文章來分析數(shù)組和列表的異同。)


          在計算機科學(xué)中,數(shù)組數(shù)據(jù)結(jié)構(gòu),簡稱數(shù)組,英文名為 array ,是由相同類型的元素的集合所組成的數(shù)據(jù)結(jié)構(gòu),分配一塊連續(xù)的內(nèi)存來存儲。利用元素的索引可以計算出該元素對應(yīng)的存儲地址。


          是不是看完這一長串理論,已經(jīng)開始暈了?那我們現(xiàn)在提煉這段話并就來用現(xiàn)實生活的例子來解析這段話,帶大家認(rèn)識到底什么是數(shù)組。


          假設(shè)我們是指揮官,我們編程時使用數(shù)組,就相當(dāng)于我們作為指揮官給指定人數(shù)的士兵布置了一個團(tuán)隊任務(wù)。而這個指定人數(shù)的隊伍,就可以視為一個數(shù)組。

          • 數(shù)組由相同類型的元素的集合所組成。這就像是現(xiàn)實中的一列士兵,他們的職業(yè)都是軍人,即所謂的類型相同,他們都是同一個連或者同一個團(tuán)的,即同一個集合。

          • 數(shù)組分配一塊連續(xù)的內(nèi)存來存儲。即同一列士兵,在做任務(wù)時,一般都會吃住在同一片區(qū)域。

          • 利用元素的索引可以計算出該元素對應(yīng)的存儲地址。士兵每天訓(xùn)練時要進(jìn)行有序的排隊,當(dāng)喊第幾號士兵時,可以通過這位士兵的回答,得知他的各種信息,例如執(zhí)行任務(wù)期間,住在哪片區(qū)域具體哪個位置。我們從平常計數(shù)報數(shù)都是從 1 開始,而計算機默認(rèn)是從 0 開始,這點要記清楚,以防之后進(jìn)行和數(shù)組相關(guān)的操作產(chǎn)生混亂。

          因此我們可知,數(shù)組就如同一列整齊的士兵,他們都是正規(guī)的軍人,他們在隊伍里有指定的位置,且通過叫號,可以知曉他們的訊息。正如軍隊里的士兵存在編號一樣,數(shù)組中的每一個元素也有著自己的下標(biāo),只不過這個下標(biāo)從 0 開始,一直到數(shù)組長度 -1。


          數(shù)組一般用來存儲具有 "一對一" 邏輯關(guān)系數(shù)據(jù)的線性存儲結(jié)構(gòu),即是在內(nèi)存中順序存儲,因此可以很好地實現(xiàn)邏輯上的順序表。


          數(shù)組在內(nèi)存中的順序存儲,具體是什么樣子呢?


          內(nèi)存是由一個個連續(xù)的內(nèi)存單元組成的,每一個內(nèi)存單元都有自己的地址。在這些內(nèi)存單元中,有些被其他數(shù)據(jù)占用了,有些是空閑的。數(shù)組中的每一個元素,都存儲在小小的內(nèi)存單元中,并且元素之間緊密排列,既不能打亂元素的存儲順序,也不能跳過某個存儲單元進(jìn)行存儲。


          這就像是宿舍分配的床位,每個宿舍有幾個指定的床位,床位號一般都是連續(xù)的,每個床位號對應(yīng)一個學(xué)生,這些學(xué)生可能有人每天都在宿舍住,有的可能搬出去住。床位號都是按順序來的,進(jìn)行安排時也不會考慮跳過哪個號進(jìn)行床位分配。


          理論性的介紹先告一段落,單單了解數(shù)組的理論知識還遠(yuǎn)遠(yuǎn)不夠,接下來我們將系統(tǒng)性的介紹數(shù)組在編程中的使用。


          數(shù)組的使用

          任何數(shù)據(jù)結(jié)構(gòu)的操作基本離不開,增刪改查這四種情況。接下來就讓我給大家介紹數(shù)組的增刪改查怎么實現(xiàn)。


          數(shù)組元素的查詢

          // 初始化
          String[] array = new String[]{'red', 'green', 'blue', 'yellow', 'white', 'black'};
          // 通過下標(biāo)進(jìn)行索引
          System.out.println(array[0]);
          System.out.println(array[1]);
          System.out.println(array[2]);
          list_array=['red', 'green', 'blue', 'yellow', 'white', 'black']
          print( list_array[0] )#red
          print( list_array[1] )#green
          print( list_array[2] )#blue

          對 python 代碼進(jìn)行講解:


          我們新建了一個長度為 6 的數(shù)組,并查詢數(shù)組 list_array 下標(biāo)為 0,1,2的元素,并將他們打印出來。


          對于數(shù)組來說,讀取元素是最簡單的操作。由于數(shù)組在內(nèi)存中順序存儲,所以只要給出一個數(shù)組下標(biāo),就可以讀取到對應(yīng)的數(shù)組元素。


          例如我們當(dāng)前新建的 list_array 數(shù)組,我們要讀取數(shù)組下標(biāo)為 3 的元素,就寫作 array_list[3];讀取的元素即為 ?yellow ,讀取數(shù)組下標(biāo)為 5 的元素,就寫作 array_list[5],讀取的數(shù)組為 black ,需要注意的是,輸入的下標(biāo)必須在數(shù)組的長度范圍之內(nèi),否則會出現(xiàn)數(shù)組越界。

          • tips:

            在 python 中,使用 list 進(jìn)行數(shù)組的新建,然后索引時,它其實是不會報錯的,這也是數(shù)組和列表的一大區(qū)別,其實本質(zhì)還是因為列表類似于動態(tài)數(shù)組,我們在別的編程語言中使用的數(shù)組,明確而言是有指定的長度的, 超越指定的長度時,它會進(jìn)行越界報錯,而動態(tài)數(shù)組的長度是沒有準(zhǔn)確規(guī)定,只要不超出內(nèi)存,即可在數(shù)組末尾一直添加元素,這點是不是和python中的列表很像呢?


          數(shù)組元素的更改

          String[] array = new String[]{'red', 'green', 'blue', 'yellow', 'white', 'black'};
          array[0] = 'orange';
          list_array=['red', 'green', 'blue', 'yellow', 'white', 'black']
          list_array[0] = 'orange'

          對 python 代碼進(jìn)行講解:


          依舊是我們的 list_array ?,現(xiàn)在我想把第一位的紅色變成橘色,那么我們直接使用下標(biāo)索引,找到 'red' ,然后將其賦值為 'orange' 即可。


          要把數(shù)組中某一個元素的值改為一個新值,也是非常簡單的操作。我們直接利用下標(biāo)索引到它,然后將其賦值為新的值就可以了。

          時間復(fù)雜度分析

          我們根據(jù)索引就可以查詢到元素的位置,若想要更改直接覆蓋掉它的值即可。因此數(shù)組元素的修改和查找的時間復(fù)雜度均為 ??。

          • tips:

            關(guān)于時間復(fù)雜度的講解,參考我之前的文章。

          數(shù)組元素的插入


          數(shù)組元素的插入分為以下幾種

          • 尾部插入
          • 中間插入
          • 超范圍插入
          在這里python只需要幾行代碼即可實現(xiàn)這一切,因為涉及到底層邏輯以及鏈表的知識,我們在此章不進(jìn)行詳細(xì)的講解,只講應(yīng)用。而python的底層實際上是 c語言寫的,所以接下來我們會對數(shù)組元素的插入進(jìn)行系統(tǒng)的介紹,其實這是 python 底層已經(jīng)幫我們做了的事情,但是要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu),我們就要從底層開始了解一個方法是怎么被實現(xiàn)的,所以我依舊對數(shù)組的插入進(jìn)行了較本質(zhì)的講解。
          • 尾部插入

          在 java 和 c 語言中,尾部插入是最簡單的方法,我們只需要對數(shù)組進(jìn)行一次循環(huán)找到要插入的位置,然后進(jìn)行賦值即可。

          • 中間插入

          而進(jìn)行中間的插入時,我們就要考慮這些:


          • 確認(rèn)數(shù)組本身是否還有空余的位置。如果沒有空余的位置,那么我們就要進(jìn)行超范圍插入了。如果有空余的位置,我們進(jìn)行下面的操作。
          • 挪位置。先為了給這個元素讓出一個位置,這個元素指定的位置之后的元素都要向后移動一個位置,不然的話,是沒有位置留給插入的那個元素的。
          • 將元素放進(jìn)騰出的那個位置。原來的元素進(jìn)行挪位操作后,該元素進(jìn)行賦值歸位,這樣元素就插入成功了。
          • 數(shù)組長度+1,正因為成功插入了一個元素,所以數(shù)組的長度進(jìn)行了變化。
          • 超范圍插入

          什么是超范圍插入?比如我定義了一個數(shù)組,長度為 6 ,而從 0 到 5 這6個位置,都有元素,數(shù)組已經(jīng)滿了,但是我們依舊想要向其中插入插入元素,這個時候我們就需要擴(kuò)大數(shù)組的長度了,可是數(shù)組的長度在創(chuàng)建時就已經(jīng)確定了,不是說變就可以輕易的改變的,所以我們通常的操作便是,創(chuàng)建一個新數(shù)組,長度是舊數(shù)組的 2 倍,再把舊數(shù)組中的元素統(tǒng)統(tǒng)復(fù)制過去,這樣就實現(xiàn)了數(shù)組的擴(kuò)容。


          以下是 java 代碼實現(xiàn)的,新建一個數(shù)組,對其進(jìn)行插入操作。雖然和我上面說的步驟幾乎是一樣的,但是代碼量可以說是很多了。

          private int[] array;
          private int size;

          public MyArray(int capacity){
          this.array = new int[capacity];
          size = 0;
          }

          /**
          * 數(shù)組插入元素
          * * index 插入的位置
          * element 插入的元素
          */

          public void insert(int index, int element) {
          //判斷訪問下標(biāo)是否超出范圍
          if(index<0 || index>size){
          System.out.println("超出數(shù)組實際元素范圍!");
          }
          //如果實際元素達(dá)到數(shù)組容量上限,則對數(shù)組進(jìn)行擴(kuò)容
          if(size >= array.length){
          resize();
          }
          //從右向左循環(huán),將元素逐個向右挪1位
          for(int i=size-1; i>=index; i--){
          array[i+1] = array[i];
          }
          //騰出的位置放入新元素
          array[index] = element;
          size++;
          }
          /**
          * 數(shù)組擴(kuò)容
          */

          public void resize(){
          int[] arrayNew = new int[array.length*2];
          //從舊數(shù)組復(fù)制到新數(shù)組
          System.arraycopy(array, 0, arrayNew, 0, array.length);
          array = arrayNew;
          }

          /**
          * 輸出數(shù)組
          */

          public void output(){
          for(int i=0; i System.out.println(array[i]);
          }
          }

          public static void main(String[] args) {
          MyArray myArray = new MyArray(10);
          myArray.insert(0,7);
          myArray.insert(1,5);
          myArray.insert(2,9);
          myArray.insert(3,8);
          myArray.insert(1,4);
          myArray.output();
          }

          而在 python 中,我們在現(xiàn)實的使用過程中,無需擔(dān)心自己是否也要像使用 java 那樣,只為處理一個插入操作,就寫了如此多的代碼,我們只要調(diào)用列表自帶的方法就可以了。


          • 列表中的 append 方法

          列表中的 append 方法,對應(yīng)數(shù)組中的尾部插入,它的底層實現(xiàn)形式類似于上文提到的java中的實現(xiàn)形式。

          list_array = ['red', 'green', 'blue']
          list_array.append('black')
          print ("更新后的列表 : ", list_array)
          #更新后的列表為['red', 'green', 'blue','black']

          對 python 代碼進(jìn)行講解:

          我們新生成的列表對其直接使用append方法,在其中輸入我們要添加的元素即可,然后我們的元素就被添加到了列表的末尾了。


          • 列表中的 insert 方法

          列表中的 insert 方法,對應(yīng)數(shù)組中的中間插入,只需要一步調(diào)用方法,即可完成 java 中那么多的判斷以及元素的插入,可見 python 的強大。又因為列表本身可以視為動態(tài)數(shù)組,其實對于長度的要求并沒有數(shù)組那么苛刻,它是可以隨意插入元素的,無需擔(dān)心長度,容量問題。

          list_array = ['red', 'green', 'blue']
          list_array.insert(0, 'black')
          print ('列表插入元素后為 : ', list_array)
          #更新后的列表為 ['black', 'red', 'green', 'blue']

          對 python 代碼進(jìn)行講解:

          對新生成的列表使用 insert 方法,insert 方法有兩個參數(shù),第一個參數(shù)為,我們要將元素插入到列表的哪個位置,第二個參數(shù)為元素內(nèi)容。該段代碼即為使用 insert 方法將 'black' 插入到列表的頭部。

          • 列表中的 extend 方法

          列表中的 extend 方法,用于在列表末尾一次性追加另一個序列中的多個值(用新列表擴(kuò)展原來的列表)??梢砸暈槭菙?shù)組擴(kuò)容的一種特殊情況。

          list_array = ['red', 'green', 'blue']
          list2=list(range(5)) # 創(chuàng)建 0-4 的列表
          list1.extend(list2) # 擴(kuò)展列表
          print ("擴(kuò)展后的列表:", list1)
          #擴(kuò)展后的列表:['red', 'green', 'blue', 0, 1, 2, 3, 4]


          數(shù)組元素的刪除

          數(shù)組的刪除操作和插入操作的過程相反,如果是在數(shù)組的最后刪除元素,那么直接去除元素即可,但是如果是在頭部或者數(shù)組的中間刪除元素,那么其后的元素都需要向前挪動 1 位。


          刪除簡單的地方在于,我們無需關(guān)心下標(biāo)是否會越界,容量是肯定不會超過申請的大小的。

          public int delete(int index)  {
          //判斷訪問下標(biāo)是否超出范圍
          if(index<0 || index>=size){
          System.out.println("超出數(shù)組實際元素范圍!");
          }
          int deleted= array[index];
          //從左向右循環(huán),將元素逐個向左挪1位
          for(int i=index; i1; i++){
          array[i] = array[i+1];
          }
          size--;
          return deleted;
          }

          python 列表中有兩種方法和數(shù)組的刪除操作匹配,即 pop 和 remove 方法。


          • 列表中的pop方法

          pop() 函數(shù)用于移除列表中的一個元素(默認(rèn)最后一個元素),并且返回該元素的值。

          list1 = ['red', 'green', 'blue']
          list1.pop()
          print ("列表現(xiàn)在為 : ", list1)
          #列表現(xiàn)在為 : ['red', 'green']
          list1.pop(1)
          print ("列表現(xiàn)在為 : ", list1)
          #列表現(xiàn)在為 : ['red']

          對 python 代碼進(jìn)行講解:


          新建一個 list1 列表,我們對其使用 pop() ,那么 list1 列表中最后一個元素被移除,這個元素即為 'blue' ,然后繼續(xù)對 list1 使用 pop 操作,此時 list1 中最后一個元素為 'green',將其移除, list1 中最后只有 'red' 一個元素了。


          • 列表中的 remove 方法

          remove() 函數(shù)用于移除列表中某個值的第一個匹配項。即當(dāng)列表中有一樣的元素的時候,使用 remove 刪除這個元素, remove 將會刪除下標(biāo)較小的。

          list1 = ['red', 'green', 'blue']
          list1.remove('red')
          print ("列表現(xiàn)在為 : ", list1)
          # 列表現(xiàn)在為 : ['green','blue']
          list1.remove('green')
          print ("列表現(xiàn)在為 : ", list1)
          # 列表現(xiàn)在為 : ['blue']

          # 有重復(fù)元素的情況
          list2 = ['red','red','green','blue','blue']
          list2.remove('red')
          print("列表現(xiàn)在為:",list2)
          # 列表現(xiàn)在為:['red', 'green', 'blue', 'blue']
          list2.remove('green')
          print("列表現(xiàn)在為:",list2)
          # 列表現(xiàn)在為:['red', 'blue', 'blue']

          對 python 代碼進(jìn)行講解:


          新建一個 list2 列表,我們對其使用 remove('red') ,那么 list2 列表中第一個 'red' 將會被移除,然后繼續(xù)對 list2 使用 remove 操作,這次我們移除列表中第一個 'blue' ,打印列表可以發(fā)現(xiàn),我們原列表中的 0 號位的 'red' 和 3 號位的 'blue' 都被刪掉了,而剩下的 'red' 和 'blue' 沒有被移除。

          時間復(fù)雜度分析

          數(shù)組的插入,我們首先要考慮數(shù)組的長度和容量,如果容量空余,我們在插入前還要為元素騰出位置,因此我們在此的時間復(fù)雜度 為 ?, 如果元素的容量已滿,我們要擴(kuò)容數(shù)組,那么這個操作的時間復(fù)雜度仍為?,綜合考慮,數(shù)組的插入操作時間復(fù)雜度為? .


          數(shù)組的刪除,無需考慮數(shù)組的長度和容量問題,只需要在刪除元素之后,改變其它元素的位置即可,因此數(shù)組的刪除操作消耗的時間在此的時間復(fù)雜度為 ? .

          數(shù)組的優(yōu)勢和劣勢

          數(shù)組的優(yōu)勢體現(xiàn)在查詢和修改元素上,我們只需要知道元素的數(shù)組下標(biāo)即可對其進(jìn)行查詢和修改,非常的方便。而這種特性也被二分查找法充分的利用了。

          數(shù)組的劣勢體現(xiàn)在它的插入操作和刪除操作上,當(dāng)插入一個元素或者刪除一個元素時,其他的元素都需要改變,這極大地影響了程序的運行效率。

          總之?dāng)?shù)組適用于,查找,修改較多,插入,刪除較少的場景下。我們下周要講的鏈表則和它的情況相反。

          流沙團(tuán)隊聯(lián)合AI悅創(chuàng)|久遠(yuǎn)·推出輔導(dǎo)班啦,包括「Python 語言輔導(dǎo)班、C++ 輔導(dǎo)班、java 輔導(dǎo)班、算法/數(shù)據(jù)結(jié)構(gòu)輔導(dǎo)班、少兒編程、pygame 游戲開發(fā)」,全部都是一對一教學(xué):一對一輔導(dǎo) + 一對一答疑 + 布置作業(yè) + 項目實踐等。QQ、微信在線,隨時響應(yīng)!

          長按識別下方二維碼,和眾多位島民一起

          把別人的頓悟,變成你的基本功


          ?花半秒鐘就看透事物本質(zhì)的人,
          ? 和花一輩子都看不清的人,
          ? 注定是截然不同的命運。

          瀏覽 59
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲中文无码字幕 | 中文字幕在线亚洲精品 | 色五月av综合 | 在线观看视频草女人啊啊 | www.AV视频在线观看 |