數據結構之線性表預習

1.簡述線性表中順序存儲結構的含義及主要元素

描述順序存儲結構需要三個屬性: 
1. 存儲空間的起始位置:數組 data , 它的存儲位置就是存儲空間的存儲位置 
2. 線性表的最大存儲容量 
3. 線性表的當前長度


數組長度 與 線性表長度區別 
- 數組長度: 
即存放線性表的存儲空間的長度,存儲分配後這個量一般是不變的。


線性表長度: 
即線性表中數據元素的個數
在任意時刻,線性表的長度應該小於等於數組的長度。

2.順序存儲結構是如何實現插入與刪除的

插入操作


插入算法的思路:


如果插入位置不合理,拋出異常
如果線性表長度大於等於數組長度,則拋出異常或動態增加容量
從最後一個元素開始向前遍歷到第 i 個位置,分別將它們都向後移動一個位置
將要插入元素填入位置 i 處
表長加1
刪除操作


刪除算法的思路:


如果刪除位置不合理,拋出異常
取出刪除元素
從刪除元素位置開始遍歷到最後一個元素位置,分別將它們都向前移動一個位置
表長減1
分析插入和刪除的時間複雜度:


最好的情況:插入或刪除的都是最後一個元素,時間複雜度 O(1) 
最壞的情況:插入或刪除的都是第一個元素,則所有其他元素都要進行移動,時間複雜度 O(n) 
平均的情況:插入或刪除第 i 個元素,需要移動 n - i 個元素,時間複雜度 O(n)


結論: 
線性表的順序存儲結構,在存、取數據時,不管是哪個位置,時間複雜度都是O(1),而插入和刪除時,時間複雜度都是 O(n)。 
適合元素個數不太變化,而更多是存儲數據的應用。


3.順序存儲結構的優缺點有哪些

從優點開始說。當我們在使用線性表的時候,我們不需要爲表中元素之間的邏輯關係而增加額外的存儲空間,而且可以快速的存取表中任意位置的元素。接下來談談缺點。如我們所見,如果我們要插入或者刪除的元素是在第一個位置,那麼無疑的,我們需要移動大量的元素來完成這樣的操作,而且限於線性表長度必須小於數組長度,如果我們需要插入大量數據,那麼很難保證空間是否充足,而如果我們要刪除大量數據的時候,無疑又會造成空間的浪費。


優點:


具有簡單、運算方便等優點,特別是對於小線性表或長度固定的線性表,採用順序存儲結構的優越性更爲突出;


缺點:


順序存儲插入與刪除一個元素,必須移動大了的數據元素,以此對大的線性表,特別是在元素的插入和刪除很頻繁的情況下,採取順序存儲很是不方便,效率低;
順序存儲空間容易滿,出現上溢,程序訪問容易出問題,順序存儲結構下,存儲空間不便擴充;
順序存儲空間的分配問題,分多了浪費,分少了空間不足上溢。


4.如何理解線性表的鏈式存儲結構

線性表的鏈式存儲結構(簡稱 鏈表)


鏈表是一種常見的基礎數據結構,是一種線性表,但是並不是按照線性的順序存儲數據,鏈表中的每一個元素,在數據結構中稱之爲節點,每一個節點中不只會存儲這個節點的值,也會存儲下一個節點的指針。

鏈表需要查找和修改值,是比較麻煩的,需要遍歷整個鏈表,複雜度爲O(n),而順序存儲結構只需要O(1),而鏈表在插入和刪除的時候就相對於順序存儲結構來說就相對簡單的多,只需要改變後繼節點就可以了,時間複雜度爲O(1),而順序存儲結構則需要O(logn),所以如果數據需要頻繁的查找和修改就使用順序存儲結構,如果只是插入和刪除那麼使用鏈表會更好些。

5.鏈表中頭指針和頭結點的區別

關於頭指針:
1.在線性表的鏈式存儲結構中,頭指針是指鏈表中指向第一個結點的指針,若鏈表有頭結點,則頭指針就是指向鏈表頭結點的指針。


2.頭指針具有標識作用,因此經常使用鏈表的名字作爲頭指針名


3.無論鏈表是否爲空,頭指針均不爲空。頭指針是鏈表的必要元素。


關於頭結點:
1.頭結點是放在第一個元素結點之前的結點,頭結點不是鏈表中的必須元素,其數據域一般無意義,(有些情況下會存放鏈表的長度,或用作監視哨等)


2.有了頭結點後,對在第一個元素結點前插入結點和刪除第一個結點,這些操作與對其他結點的操作就相同了。


6.如何實現單鏈表的插入與刪除

插入:

{   //在帶有頭結點的單鏈表L中的第i個結點前插入元素e
    LinkList p,s;
    int j;
    p=L;j=0;  //①聲明一結點p指向鏈表頭結點,初始化j從0開始;
    while(p->next&&j<i-1){ 
    p=p->next;
    j++;
    }  //②尋找第i-1個結點並讓p指向此結點
    if(j!=i-1)  return false;   //③若i的位置不合理則報錯
    if((s=(LNode*)malloc(sizeof(LNode)))==NULL)  exit(1);     //④查找成功,在系統中生成一個空結點s;
    s->data=e;    //⑤將數據元素e複製給s->data;
    s->next=p->next;p->next=s;   //⑥插入操作(關鍵語句)
    return true;   //⑦返回成功;
}     

刪除

{   //刪除帶有頭結點的單鏈表L中的第i個結點,並饒讓e返回其值
    LinkList p,q;
    int j;
    p=L;j=0;  //①聲明一結點p指向鏈表頭結點,初始化j從0開始;
    while(p->next->next&&j<i-1&&p->next){ 
    p=p->next;
    j++;
    }  //②尋找第i-1個結點並讓p指向此結點
    if(j!=i-1)  return false;   //③若i的位置不合理則報錯
    q=p->next;       //④若查找成功,q指向其後繼
    p->next=p->next;  //⑤結點q的後繼成爲結點p的後繼
    e=q->data;        
    free(q);          //⑥將被刪除的元素的值賦給e,釋放被刪除結點的空間
    return true;   //⑦返回成功;
}     //LinkDelete_L


7.順序存儲與鏈式存儲中插入刪除操作的效率問題

1、無論是單鏈表的插入操作還是刪除操作,都是由兩部分組成的:一是遍歷查找第i個元素,二是實現插入或刪除操作。


就整個算法而言,他們的時間複雜度都是O(n),這樣來看的話,再不知道要找的第i個元素所處的位置時,單鏈表的插入刪除操作和順序存儲是沒有什麼優越性的。


但是!如果知道要插入或者刪除的元素的位置時,鏈式存儲就表現出它的優越性了。假如我們要在a10與a11之間插入10個元素,那麼順序存儲每插入一個元素後面的元素就要移動一次位置,每次都是O(n)。而鏈式存儲,只需要第一次時找到要插入的那個位置,後面的就只是賦值移動指針而已,時間複雜度爲O(1)。


因此,可以得出一個結論:對於插入或者刪除操作越頻繁的操作,單鏈表的效率優勢就越是明顯。


8.如何實現單鏈表的整體創建

一、單鏈表的整表創建


創建單鏈表的過程是一個動態生成鏈表的過程,從“空表”的初始狀態起,依次建立各元素結點並逐個插入鏈表。


單鏈表整表創建的算法思路如下:


1)聲明一結點P 。2)初始化一空鏈表L 。3)建立一個帶頭結點的單鏈表,即讓L的頭結點的指針指向NULL。4)循環實現後繼結點的賦值和操作。


單鏈表創建的方法有兩種:頭插法和尾插法。


1、頭插法—把新加進的元素放在表頭後的第一個位置。具體操作就是首先是新結點的next指向頭結點之後,表頭的next指向新結點。
typedef float ElemType;  
typedef struct Node  
{  
    ElemType data;//數據域  
    struct Node *Next;//指針域  
}Node;  
typedef struct Node* LinkList;  
void CreateLinkList(LinkList L,int n)  
{  
    LinkList p;  
    int i;  
  
    srand(time(0));  
    L = (LinkList)malloc(sizeof(Node));//建立表頭  
    L->Next = NULL;  
  
    for(i = 0;i < n;i++)  
    {  
        p = (LinkList)malloc(sizeof(Node));  
        p->data = rand()%100 + 1;  
        p->Next = L->Next;  
        L->Next = p;  
    }  
  
  
}  
 2、尾插法—新結點都插入到最後。

尾插法程序如下:
[cpp] view plain copy

typedef float ElemType;  

typedef struct Node  

{  

    ElemType data;//數據域  

    struct Node *Next;//指針域  

}Node;  

typedef struct Node* LinkList;  

void CreateLinkList(LinkList L,int n)  

{  

    LinkList p,r;  

    int i;  

  

    srand(time(0));  

    L = (LinkList)malloc(sizeof(Node));//建立表頭  

      

    r = L;  

  

    for(i = 0;i < n;i++)  

    {  

        p = (LinkList)malloc(sizeof(Node));  

        p->data = rand()%100 + 1;  

        r->Next = p;  

        r = p;  

    }  

  

    r->Next = NULL;  

}  

9.順序存儲結構與鏈式存儲結構的優缺點

(一)順序存儲結構和鏈式存儲結構的優缺點比較,以及使用情況。
1 優缺點
① 順序存儲時,相鄰數據元素的存放地址也相鄰(邏輯與物理統一);要求內存中可用存儲單元的地址必須是連續的。
優點:存儲密度大(=1),存儲空間利用率高。缺點:插入或刪除元素時不方便。
②鏈式存儲時,相鄰數據元素可隨意存放,但所佔存儲空間分兩部分,一部分存放結點值,另一部分存放表示結點間關係的指針
優點:插入或刪除元素時很方便,使用靈活。缺點:存儲密度小(<1),存儲空間利用率低。


2 使用情況
順序表適宜於做查找這樣的靜態操作;鏈表宜於做插入、刪除這樣的動態操作。
若線性表的長度變化不大,且其主要操作是查找,則採用順序表;
若線性表的長度變化較大,且其主要操作是插入、刪除操作,則採用鏈表。


3 比較
順序表與鏈表的比較
基於空間的比較
存儲分配的方式
順序表的存儲空間是靜態分配的
鏈表的存儲空間是動態分配的
存儲密度 = 結點數據本身所佔的存儲量/結點結構所佔的存儲總量
順序表的存儲密度 = 1
鏈表的存儲密度 < 1
 
基於時間的比較
存取方式
順序表可以隨機存取,也可以順序存取
鏈表是順序存取的
插入/刪除時移動元素個數
順序表平均需要移動近一半元素
鏈表不需要移動元素,只需要修改指針


10.如何理解靜態鏈表、循環鏈表和雙向鏈表

雙向鏈表,也叫雙鏈表
雙向鏈表中不僅有指向後一個節點的指針,還有指向前一個節點的指針。第一個節點的"前連接"指向NULL,最後一個節點的"後連接"指向NULL。


這樣可以從任何一個節點訪問前一個節點,也可以訪問後一個節點,以至整個鏈表。一般是在需要大批量的另外儲存數據在鏈表中的位置的時候用。


由於另外儲存了指向鏈表內容的指針,並且可能會修改相鄰的節點,有的時候第一個節點可能會被刪除或者在之前添加一個新的節點。這時候就要修改指向首個節點的指針。


有一種方便的可以消除這種特殊情況的方法是在最後一個節點之後、第一個節點之前儲存一個永遠不會被刪除或者移動的虛擬節點,形成一個循環鏈表。這個虛擬節點之後的節點就是真正的第一個節點。這種情況通常可以用這個虛擬節點直接表示這個鏈表。




循環鏈表
在一個循環鏈表中, 首節點和末節點被連接在一起。這種方式在單向和雙向鏈表中皆可實現。要轉換一個循環鏈表,你開始於任意一個節點然後沿着列表的任一方向直到返回開始的節點。循環鏈表可以被視爲"無頭無尾"。


循環鏈表中第一個節點之前就是最後一個節點,反之亦然。循環鏈表的無邊界使得在這樣的鏈表上設計算法會比普通鏈表更加容易。對於新加入的節點應該是在第一個節點之前還是最後一個節點之後可以根據實際要求靈活處理,區別不大。


另外有一種模擬的循環鏈表,就是在訪問到最後一個節點之後的時候,手工跳轉到第一個節點。訪問到第一個節點之前的時候也一樣。這樣也可以實現循環鏈表的功能,在直接用循環鏈表比較麻煩或者可能會出現問題的時候可以用。




其它
鏈表中的節點不需要以特定的方式存儲,但是集中存儲也是可以的,主要分下面這幾種具體的存儲方法:


共用存儲空間:鏈表的節點和其它的數據共用存儲空間,優點是可以存儲無限多的內容(不過要處理器支持這個大小,並且存儲空間足夠的情況下),不需要提前分配內存,存儲一個申請一個,如C語言的MALLOC;缺點是由於內容分散,有時候可能不方便調試。


獨立存儲空間:一個鏈表或者多個鏈表使用獨立的存儲空間,一般用數組或者類似結構實現,優點是可以自動獲得一個附加數據:唯一的編號/索引,並且方便調試;缺點是不能動態的分配內存。當然,另外的在上面加一層塊狀鏈表用來分配內存也是可以的,這樣就解決了這個問題。這種方法叫做數組模擬鏈表,但是事實上只是用表示在數組中的位置的下標索引代替了指向內存地址的指針,這種下標索引其實也是邏輯上的指針,整個結構還是鏈表,並不算是被模擬的(但是可以說成是用數組實現的鏈表)。


鏈表用來構建許多其它數據結構,如堆棧,行列和他們的衍生。


節點的數據域也可以成爲另一個鏈表。通過這種手段,我們可以用列表來構建許多鏈性數據結構;這個實例產生於Lisp編程語言,在Lisp中鏈表是初級數據結構,並且現在成爲了常見的基礎編程模式。 有時候,鏈表用來生成聯合數組,在這種情況下我們稱之爲聯合數列。這種情況下用鏈表會優於其它數據結構,如自平對分查找樹(self-balancing binary search trees)甚至是一些小的數據集合。不管怎樣,一些時候一個鏈表在這樣一個樹中建立一個節點子集,並且以此來更有效率地轉換這個集合。

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