-
線性表的鍊式存儲實作
線性表的鍊式存儲實作通常單連結清單. 單連結清單由一系列在記憶體中相連的結點組成, 每個結點均含有資料域和指針域, 資料域存儲資料, 指針域存儲指向下一個結點的指針. 單連結清單的結構如圖:
資料結構之線性表的鍊式存儲實作(連結清單) 單連結清單資料結構中的概念:
結點 node: 結點由資料域和指針域組成, 資料域中可以是任意類型的資料包括結構體甚至其他資料結構, 指針域中是指向連結清單下一個結點的指針.
頭結點 head node: 頭結點也稱表頭 啞結點, 資料域無意義, 指針域存儲指向連結清單第一結點的指針, 并将其看作指向目前連結清單的指針, 注意約定頭結點是連結清單的第0個結點, 而非第1個.
頭指針 head pointer: 指向連結清單頭結點的指針, 無頭結點時指向連結清單第一個結點.
位置 position: 一個結點在連結清單中占據一個位置, 頭結點的位置為0.
表長 list length:表中結點的個數(除頭結點)
前驅 previous node: 目前結點的前一個結點.
後繼 next node: 目前結點的下一個結點.
空表 empty list: 隻有頭結點的的連結清單, 表長為0.
- 存儲結構僞代碼
struct node;
typedef struct node *ptr_to_node;
typedef ptr_to_node list;
typedef ptr_to_node nodeptr; // 指向結點的指針
int is_empty(list l); // 判斷連結清單l是否為空
int is_last(list l, nodeptr node); // 判斷pos所指向的結點是否為最後一個結點
int get_length(list l); // 擷取連結清單長度
int get_position(list l, element_type data); // 擷取資料域為data的結點的位置
nodeptr get_current(list l, int pos); // 擷取指向pos位置的結點的指針
nodeptr get_previous(list l, int pos); // 擷取指向pos位置前一個結點的指針
void init_list(); // 初始化連結清單
nodeptr find_node(list l, element_type data); // 查找資料域為data的結點, 傳回指向其的指針
bool insert_node(list l, int pos, int data); // 在位置pos處插入一個資料域為data的結點
bool delete_node(list l, element_type data); // 删除資料域為data的結點
bool delete_list(list l); // 删除整個連結清單
struct node {
element_type element;
nodeptr next;
};
連結清單結構如圖:
- 實作
is_empty
函數
思路: 頭結點的next指針指向NULL時連結清單為空表.
int is_empty(list l)
{
return l->next == NULL;
}
- 實作
is_last
函數
思路: pos結點的next指針指向NULL時, pos指向最後一個結點.
int is_last(list l, nodeptr node)
{
return node->next == NULL;
}
- 實作
get_length
函數
思路: 從指向第1個結點的指針開始, 逐個通路結點直到遇到NULL指針.
int get_length(list l)
{
nodeptr node_ptr = l->next;
int count = ;
while(node_ptr != NULL) {
node_ptr = node_ptr->next;
count++;
}
return count;
- 實作
get_position
函數
思路: 從從指向第1個結點的指針開始, 逐個通路結點直到資料域為data的結點
int get_position(list l, element_type data)
{
nodeptr node_ptr = l->next;
int count = ;
while(node_ptr->element != data) {
node_ptr = node_ptr->next;
count++;
}
}
- 實作
get_current
函數
思路: 從第1個位置開始, 逐個通路結點直到pos位置.
nodeptr get_current(list ;, int pos)
{
if(pos >= && pos <= get_length()) {
nodeptr node_ptr = l->next;
for(int i = ; i < pos; i++) {
nodeptr = nodeptr->next;
}
return node_ptr;
}
else {
error("Wrong position!");
return NULL;
}
}
- 實作
get_previous
函數
思路: 從第1個位置開始, 逐個通路結點直到pos位置的前一個位置.
nodeptr get_previous(list ;, int pos)
{
if(pos >= && pos <= get_length()) {
nodeptr node_ptr = l;
for(int i = ; i < pos - ; i++) {
nodeptr = nodeptr->next;
}
return node_ptr;
}
else {
error("Wrong position!");
return NULL;
}
}
- 實作
init_list
函數
思路: 配置設定頭結點的記憶體, 并将其指針域指向NULL.
list init_list()
{
list l = malloc(sizeof(struct node));
if( l != NULL) {
l->element = ;
l->next = NULL;
}
return l;
}
- 實作
find_node
函數
思路: 從連結清單l的第1個結點開始, 将結點的資料域與data比較, 若相同傳回目前節點的指針node_ptr, 若不同将node_ptr後移, 繼續比較直到連結清單末尾.
nodeptr find_node(list l, element_type data)
{
nodeptr node_ptr = l->next; // 從連結清單第1個結點開始
while(tmp_node != NULL && node_ptr->element != data)
node_ptr = node_ptr->next;
return node_ptr;
}
- 實作
insert_node
函數
思路:
資料結構之線性表的鍊式存儲實作(連結清單)
step1: 擷取指向插入位置前一個結點的指針previous
step2: 建立要插入的結點, 并設定資料域為data
step3: 設定要插入結點的指針域為previous->next(指向原位置3的結點)
step4: 設定previous的指針域設定為指向要插入的結點
bool insert_element(list l, int pos, element_type data)
{
if(pos >= && pos <= get_length(l) + ) {
nodeptr previous = get_previous(l, pos);
nodeptr tmp_node = malloc(sizeof(struct node));
if(tmp_node != NULL) {
tmp_node->element = data;
tmp_node->next = previous->next;
previous->next = tmp_node;
retur true;
}
else {
error("Out of space!");
return false;
}
}
else {
error("Wrong position!");
}
}
- 實作
delete_element
函數
思路:
step1: 擷取指向删除位置前一個結點的指針previous
step2: 擷取指向删除位置結點的指針current
step3: 設定删除位置前一個結點的指針域指向删除位置後一個結點
step4: free目前位置結點記憶體
void delete_element(list l, int pos)
{
if (pos >= && pos <= get_length(l)) {
nodeptr previous = get_previous(l, pos);
nodeptr current = previous->next;
previous->next = current->next;
free(current);
return true;
}
else {
printf("Position is wrong!\n");
return false;
}
}
- 實作
delete_list
函數
step1: 記錄頭指針指向的位置, 并将頭指針指向NULL
step2: 逐個free結點記憶體
void delete_list(list l)
{
nodeptr recorder = l->next;
nodeptr tmp_node = NULL;
l->next = NULL;
while (recorder != NULL) {
tmp_node = recorder->next;
free(recorder);
recorder = tmp_node;
}
}