在使用陣列之前,陣列的大小要提前指定,當事前無法對錶的大小進行估算的時候,勢必需要定義乙個很大的陣列,防止溢位,因此這就可能會浪費大量的記憶體空間。
對錶進行插值或刪除操作時,所有插值或刪除位置後的資料都需要進行移位,時間成本的開銷就避免不了,最壞的情況是o(n).
如果採用插值的方式來建立乙個列表,顯然時間的開銷是很大的。
總之因為插入和刪除的執行時間是如此的慢以及表的大小必須事先已知,所以簡單的陣列一般不會用來實現表這種資料結構。
為了避免插入和刪除過程中出現的時間線性開銷,我們需要允許表可以不連續的儲存,否則表的部分或全部需要整體移動。鍊錶是針對以上存在的問題的解決方案。鍊錶由一系列不必在記憶體中相連的結構組成,每個結構均含有表元素和指向包含該元素後繼元素的結構的指標,我們將這個指標稱為next指標(雙向鍊錶應該會再有乙個前向的指標)。最後乙個單元中的next指向空指標null。
前面說了那麼多,當然還是碼**加注釋最直接啦。
//在標頭檔案內定義表和操作函式的原型
#ifndef _list_h
struct node; //宣告有乙個表節點單元的結構體
typedef int elementtype; //將結構體內的成員型別重定義,這樣就可以修改這一處地方就可以按照需要改變資料型別
typedef struct node *ptrtonode; //重定義指向node型別的指標型別,方便後面的型別定義
typedef ptrtonode list; //相當於 node *list 一般用來指向表頭位置
typedef ptrtonode position; //相當於 node *position 用來指向表中指定的位置
list makeempty(list l); //將乙個鍊錶清空成空表
int isempty(list l); //判斷表是否為空
int islast(position p,list l); //判斷p指向的位置是否為鍊錶的末尾
position find(elementtype x,list l); //返回鍊錶中元素x所在的位置
void delete(elementtype x,list l); //刪除鍊錶中x元素
position findprevious(elementtype x,list l); //找到元素x前乙個單元的位置
void insert(elementtype x,list l,position p); //在p指向的位置後邊插入乙個元素x
void deletelist(list l); //刪除鍊錶,並**刪除掉的單元,剩下乙個空表
//position header(list l);
//position first(list l);
//position advance(position p);
//elementtype retrieve(position p);
#endif
// _list_h
#include
#include
#include
#include "list.h" //將標頭檔案包含進來
struct node
; //定義了node節點的結構,包括成員元素和指向下乙個節點的next指標
#include
#include
#include
#include
"list.h"
struct node
;list makeempty(list l)
int isempty(list l)
int islast(position p,list l)
position find(elementtype x, list l)
position findprevious(elementtype x, list l)
void delete(elementtype x, list l)
//p->next = p->next->next;
//free(p->next);
}void insert(elementtype x, list l, position p)
void deletelist(list l)
}int main()
printf("list->element = %d\n",mylist->element);
printf("list->next->element = %d\n",mylist->next->element);
p = find(3,mylist);
printf("find 3 in mylist = %d\n",p->element);
p = findprevious(3,mylist);
printf("previous element of 3 = %d\n",p->element);
delete(2,mylist);
p = find(2,mylist);
//printf("debug = %d\n",p->element);
if(p ==
null)
printf("cant find element 2 in mylist.\n");
p = find(4,mylist);
if(islast(p,mylist))
printf("position of element 4 is last of mylist.\n");
deletelist(mylist);
if(isempty(mylist))
printf("mylist has been deleted!\n");
return
0;}
最終的輸出如下:
需要說明的是在使用鍊錶的時候要首先動態申請一段記憶體,不然定義的mylist可能指向的是重要的資料,會有可能發生意想不到的問題!!!
對於函式的定義都很簡單,沒有太多需要解釋的,但是在我自己寫delete函式的時候卻發生函式不能正常執行下去的問題。將**特別貼出以作說明:
void
delete(elementtype
x, list
l) //p->next = p->next->next;
//free(p->next);
}
可見之間使用free(p->next);這就話不能正常執行程式,而必須通過乙個暫態量tmpnode來刪除,這其中的原因在什麼地方呢?其實在學習資料結構時養成乙個時時畫圖來理解的習慣是很好的。
從圖中可以很清楚的看到 ,如果不定義乙個中間變數tmpnode,那麼直接執行free(p->next);就會將x元素後乙個單元給刪除,而且鍊錶也斷了,從而程式也就崩潰了。對於這種低階錯誤,我想也就我這種剛學習的菜鳥才會遇到,但也希望在這裡可以給自己乙個教訓,也給可能看到這段文字的朋友一點提示,學習資料結構時常畫畫圖,會避免很多問題。
第一次正兒八經的編輯部落格,排版自己也覺得太low了,哈哈!
單向迴圈鍊錶的簡單實現 資料結構學習(二)
單向迴圈鍊錶與單鏈表類似,不同之處在於 單鏈表尾指標為null,單向迴圈鍊錶尾指標指向頭結點。當需要判斷鍊錶是否結束時,單鏈表的判斷方法是判斷尾指標是否為空,單向迴圈鍊錶則是判斷尾指標是否指向頭結點。以下是單向迴圈鍊錶的簡單實現和輸出。include using namespace std stru...
基本資料結構學習總結 單向鍊錶
查詢 插入 刪除 兩種 1 鍊錶中的環問題很多演算法都涉及到了鍊錶的環問題,不得不說這些問題很有意思這個問題就是通過兩個指標,一快一慢,同時從根節點出發,如果最後能相遇,那麼說明有環 這個問題也是通過兩個快慢指標解決的,只不過快指標的速度要是慢指標的兩倍。因為當快指標與慢指標相遇時,快指標是一定比慢...
資料結構學習記錄 鍊錶1
單向鍊錶 單向鍊錶的每乙個結點都用乙個結構表示,該結構由資料和指向該結構的指標組成。乙個double型別的單向鍊錶結點 typedef struct node node 乙個自定義資料型別的單向鍊錶結點 typedef struct book book typedef struct a node o...