線形表的複習--嘟嘟胖

什麼是線形表? <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

答:一種數據結構,簡單的說, N 個數據元素的有限序列。

線性結構的特點:

只有一個首結點和尾結點;

除首尾結點外,其他結點只有一個直接前驅和一個直接後繼。

線性表順序存儲特點:

① 邏輯上相鄰的數據元素,其物理上也相鄰;

② 若已知表中首元素在存儲器中的位置,則其他元素存放位置亦可求出(利用數組下標)。

1 :一個一維數組M,下標的範圍是0到9,每個數組元素用相鄰的5個字節存儲。存儲器按字節編址,設存儲數組元素  M[ ]的第一個字節的地址是98,則M [ ] 的第一個字節的地是  ______      

  解: 地址計算通式爲

 LOC(ai)    = LOC(a1) + L * i-1

    因此: LOC( M[3] ) = 98 + 5 × (3-0) =113

線形表的實現:

定義該數據結構:

#define LIST_INIT_SIZE  100  // 初始化分配量, 100 個元素爲默認的 線性表的容量            

    #define LISTINCREMENT 10    // 線性表存儲空間的分配增量

    Typedef struct {

    Elemtype *elem ;         // 定義一個指針,用於存放線性表的基址

    Int length ;             // 定義線性表的長度

    Int listsize ;}sqlist    // 當前線性表分配到的容量

 

創建一個線性表:即初始化一個線性表,構造一個空的線性表

   Status initList_sq (sqlist &L) {

    L.elem = (ElemType *) malloc (LIST_INIT_SIZE*sizeof(ElemType))

    If (!L.elem) exit(OVERFOLOW);

L.lengh = 0 ;

L.listsize = LIST_INIT_SIZE ;

Return OK }

 

順序表的插入操作(重要,必須倒背如流)

思路:

①  插入操作應該必須知道些什麼呢?

    答:插到哪個線性表,和插到該線性表的什麼位置,還有插的元素,所以該插入函數有三個參數 &L , int I ,elemtype e .

②  插入操作中會有什麼可能出現的錯誤呢?

 A: 插入的位置應該是邏輯上成立的 1 =< I <= length(L)+1]

B: 如果線性表已經裝滿了,應該分配新的空間

          Length>=listsize 時候說明滿了

          Newbase = (elemtype *) realloc (L.elem,

( L.listsize + LISTINCREMENT ) *sizeof(elemtype));

  插入後,會對別的元素造成什麼樣的影響?

  如果插入的位置是 I ,那麼 從 I ->length(L) 都將被移動,共需移動元素 N-I+1   很明顯,應該從最右邊的元素下手,依次將 I -> n 的元素右移。 P 是指向最後一個元素的指針,    *(P +1)= *P , 最後應該完成掃尾工作 ++length .

下面寫出原碼 :      

  Void List_insert_sq(&L , int I ,elemtype e .) {

      if (i<1 || i>length(L)+1); return Error;   // 插入的位置應該是邏輯上成立

if (L.length >= L.listsize ) {   // 如果線性表已經裝滿了,應該分配新的空間

Newbase = (elemtype *) realloc (L.elem,

L .listsize + LISTINCREMENT *sizeof(elemtype));

       If (!newbase = 0 )  exit(OVERFLOW)

L.elem = Newbase;

L.Listsize = .listsize + LISTINCREMENT ;  }

       Q = &(L.elem[i-1]);  // 插入的位置

        For (P = &(L.elem[L.length-1]) ; P>=Q; P--)  {

          *(P +1)= *P ; }  // 依次將 I -> n 的元素右移

          *P = e ;

          ++L.Length ;   }

                

分析上程序的時間複雜度  

最壞的情況下是: 插入的位置是 1 ,將移動 N-I+1 個元素,插入的位置的概率是 1/n+1, 所以平均算法時間複雜讀是 O(N/2) ;

順序表的刪除操作(重要,必須倒背如流)

思路:

1 刪除操作應該必須知道些什麼呢?

答:刪除哪個線性表,和刪除該線性表的什麼位置,返回刪除元素的值,所以該插入函數有三個參數 &L , int I ,elemtype e .

2 刪除操作會出現什麼可能的錯誤?

答:刪除的元素應該在線性表內   1=< I <= length

3 刪除後會對周圍元素造成什麼樣的影響?

答:刪除的位置如果是 I ,那麼 i+1 N 的元素都將會左移一位   * P-1 =*P

很明顯,應該把從線性表的左邊移動,此前把 *P 賦給 e , 最後掃尾 –Length

下面給出原碼:

Status list_delete_sq (&L , int I ,elemtype e .) {

   If (i<1 || i>length(L)) then return error ;

   p = L.elem[i-1] ;

    E = *p;

    Q = L.elem + L.length-1;

    For (p; p<=q ; p++)

          * P-1 =* P ;

     ---L.length ;  }

分析上程序的時間複雜度  

最壞的情況下是: 刪除的位置是 1 ,將移動 N-I 個元素,插入的位置的概率是 1/n+1, 所以平均算法時間複雜讀是 O((N-1)/2) ;

 

關於 MALLOC REALLOC 的理解

首先看一下下面的 C 程序片斷:

Elemtype malloc(size)    // Elemtype 指的是數據類型,比如 INT ,那就意味着一個指針指示 4 個字節

Elemtype realloc( 原指針, SIZE)      ,即一個元素是 4 個字節。

#include <malloc.h>

char  *p;

p = (char * ) malloc (10);

p = (char * ) realloc (p,20);

函數首先定義了一個字符型的指針 p ,然後爲指針 p 分配了一個 10 個字節大小的內存空間,接着將這個內存塊的大小增加到 20 個字節。關於 realloc 究竟在哪裏分配的問題,完全由實現標準庫的程序決定。它可能在原來的地方擴充,也有可能全部另行分配(想想,如果現在要擴大存儲塊,而後面的地方已經被分配出去另有他用了,你怎麼可能在原位擴充呢?)。具體情況我們不必考慮,從抽象的層次上理解其功能就夠了。

 

順序表的定位操作:(巧妙的設計)

思路:要求查找線性表中是否有與 e 相同的元素,如果有則返回該元素的序號,否則返回 0

1. 定位過程必須知道什麼?

答: 對哪個表進行定位,返回與哪個數相等的序列號。所以需要兩個參數  

2.  怎麼進行比較控制?

答: 須對線性表中的元素都進行比較,所以應該知道線性表的長度,用一個循環依次取出每個元素比較。找到回返回序號。否則返回 0

 Int locate_list-sq (&L,e)  {

For (I = 1 ; i<=L.length&&!(e==L.elem[i-1]);++i) {}

 If (I<=L.length) then reture I

 Else return 0 ; }

    

該算法的巧妙之處在於 巧妙的利用了 ++i,意思是在 L 查找不到相等的元素後跳出循環, I 已經先加上 1 了,所以 I>L.length, 返回的值是 0

分析上程序的時間複雜度  

最壞的情況下是:找到符合條件的元素在最後一個,所以時間複雜度是 O L.Length

線性表之間的操作:

1 線性表 LA LB ,求 A=AUB 

思路:求兩線性表的並,注意集合的定義,沒有相同的元素!,一個循環解決問題

    Void union(LA,LB) {

       For (I = 1, i<=LB.length;i++){

        Getelem(LB,I,e);

          If (!locateelem(LA,e));

          Listinsert(LA,++LA.length+1,e) }

2 線性表 LA LB 中元素是按非遞減有序排列,求 LC=LAULB

思路:初始化一個線性表 LC ,將 LA LB 中元素比較,小的進 LC 。最後再掃尾

      Void mergelist(LA,LB,LC) {

        Init(LC);

         I=j=k=1 ;

         While (i<=la.length && j<=lb.length)

         {   Getelem(la,I,ai)  ; Getelem(la,j,ai) ;}

          If (ai<=bi)  {listinsert(LC, k++,ai) ; i++}

          Else {listinsert(LC,++k++,bi) ; J++}

       While(i<=la.length) {getelem(la,i++,ai) ;listinsert(LC, k++,ai);

       While(j<=lb.length) {getelem(lb,j++,bi) ;listinsert(LC, k++,bi);

 

線性表的鏈式表示和實現

鏈式存儲特點

答: 邏輯上相鄰,物理上不一定相鄰

 

在單鏈表中,除了首元結點外,任一結點的存儲位置由其直接前驅結點的鏈域的值指示

頭結點 是在鏈表的首元結點之前附設的一個結點;數據域內只放空表標誌和表長等信息 ;

首元結點 是指鏈表中存儲線性表第一個數據元素 a1 的結點。

單鏈表是非隨機訪問的儲存結構,它的 I 結點的存儲位置包含在 i-1 個結點的信息中。

對單鏈表的訪問操作 GETELEM

怎麼訪問 LINKLIST 中任一指定的結點?

答:與順序表不同,順序表只需要知道線性表的基址,再加上偏移量就可以得出。而鏈表的物理存儲位置可能是不相鄰的,因此我們必須從頭結點開始,纔可以找出某結點的存儲位置。

那怎麼控制呢?

答:如果訪問的是第 5 個元素,那我們只需要找到 5-1=4 個元素,就可以訪問它了。我們可以設置一個計數器控制循環,一直訪問到 i-1 個元素。

怎麼控制查詢範圍的錯誤呢?

       答:如果 i-1 個元素的指針域爲空,那就說明 i-1 是鏈表的最後一個結點,沒有 I 結點,返回錯誤。如果查詢的是 <1 的結點,返回錯誤。

  

下面給出算法:

     Status Getelem(linklist L, int I, elemtype e) }

      P=L->next ; j=1;

       While ( p && j < I )  {

          P = p->next ;

++J }

        If ( !p && j > i)  returnerror ;

         E = p->data ;

         Return OK;  }

單鏈表的插入操作:

思路: 在順序鏈表中,在 I 前插入一個元素,只需要將 N-I+1 個元素都向右移動一位首先將指針移動到表尾元素    *(p+1)=*p . 但是鏈表在物理上的存儲空間是不相鄰的,第 I 個元素的物理位置是保存在第 I-1 個元素的指針域裏,所以,首先,我們必須找到第 I-1 個元素,也就是我們需要得到第 I-1 個元素的指針。

怎麼能夠得到第 I-1 個元素的指針呢?

答: L 是頭指針,指向頭結點。如果我們想得到指向 I-1 個元素的指針,我們應該將 L 移動 I - 1 次。所以應該注意,循環 I-1 次 。

如果我們想要插入的位置不在 1 <=i<=n+1 呢?

答:如果插入的位置超出表長,怎麼判斷超出了表長?如果一個鏈表有 6 個元素,那麼從 1~7 的插入位置都是合理的,如果插入的位置是 7 ,那麼 I-1 個元素的既 6 的指針是存放在第 5 個元素裏的。所以 I-1 元素的指針不爲空。那麼如果剛剛超出表長一位,要求插入的位置是 8 ,那麼 I-1 個元素即 7 的指針是存放在 6 裏面的,而表長是 6 ,所以 6 的指針爲空。   由此我們得出,看是否超出表長,只需要判斷 I-1 個元素的指針是否爲空。其次,插入位置當然不能小於 1

下面是源碼:

    Status listinsert_link (linklist L, int I , elemtype e)  {

      P = L  ;  j = 0 ;

     While( p && j < i-1  ) {p=p->next , ++j}

     If (!P && j > i-1)  returnerror ;

     S = (linklist) malloc (sizeof(Lnode)) ;

     s->next = p-.next  ;

     p-next = s ;

     s->data = e ;

     return OK ; }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章