表 (list)
表(list)是常見的數據結構。從數學上來說,表是一個有序的元素集合。在C語言的內存中,表儲存為分散的節點(node)。每個節點包含有一個元素,以及一個指向下一個(或者上一個)元素的指針。如下圖所示:
表: 橙色儲存數據,藍色儲存指針
圖中的表中有四個節點。第一個節點是頭節點(head node),這個節點不用于儲存元素,只用于標明表的起始。頭節點可以讓我們方便的插入或者刪除表的第一個元素。整個表中包含有三個元素(5, 2, 15)。每個節點都有一個指針,指向下一個節點。最后一個節點的指針為NULL,我們用“接地”來圖示該指針。
表的功能與數組(array)很類似,數組也是有序的元素集合,但數組在內存中為一段連續內存,而表的每個節點占據的內存可以是離散的。在數組中,我們通過跳過固定的內存長度來尋找某個編號的元素。但在表中,我們必須沿著指針聯系起的長鏈,遍歷查詢元素。此外,數組有固定的大小,表可以根據運行情況插入或者刪除節點,動態的更改大小。表插入節點時需要從進程空間的堆中開辟內存空間,用以儲存節點。刪除節點可以將節點占據的內存歸還給進程空間。
刪除節點, free釋放內存
?
插入節點,malloc開辟內存
?
表 有多種變種。上面的表中,指針指向是從前向后的,稱為單向鏈表(linked list)。還有雙向鏈表(double-linked list),即每個節點增加一個指向前面一個元素的指針。以及循環鏈表(tabular list),最后一個元素的指針并不為NULL,而是指向頭節點。不同類型的鏈表有不同的應用場景。
雙向鏈表
?
循環鏈表
?
雙向循環鏈表
?
單向鏈表的C實現
一個數據結構的實現有兩方面: 1. 數據結構的內存表達方式; 2. 定義在該數據結構上的操作。我們這里實現最簡單的單向鏈表。表所支持的操作很靈活多樣,我們這里定義一些最常見的操作。每個操作都寫成一個函數。
/* By Vamei */#include <stdio.h> #include <stdlib.h>
typedef struct node *LIST;
typedef struct node *position;
/* node,節點 */ struct node {int element;position next; }; /*
* operations (stereotype)
* 操作
*/
LIST init_list(void); void delete_list(LIST);
int is_null(LIST);
void insert_node(position, int); void delete_node(LIST, position);
position find_last(LIST); position find_value(LIST, int); position find_previous(LIST, position);
void print_list(LIST);
/* for testing purpose */ void main() {LIST L;position np;int i;/* elements to be put into the list */int a[] = {1, 3, 5, 7, 9};/* initiate a list */L = init_list();print_list(L);/* insert nodes. Insert just after head node */for (i=4; i>=0; i--) {insert_node(L, a[i]);}print_list(L);/* delete first node with value 5 */np = find_value(L, 5);delete_node(L, np);print_list(L);/* delete list */delete_list(L);/* initiate a list */L = init_list();print_list(L);/* insert nodes. Insert just after head node */for (i=4; i>=0; i--) {insert_node(L, a[i]);}print_list(L);/* delete list */delete_list(L); }/** Traverse the list and print each element
* 打印表*/ void print_list(LIST L) {position np;if(is_null(L)) {printf("Empty List\n\n");return;}np = L;while(np->next != NULL) { np = np->next;printf("%p: %d \n", np, np->element);}printf("\n");}/** Initialize a linked list. This list has a head node* head node doesn't store valid element value
* 創建表*/ LIST init_list(void) {LIST L;L = (position) malloc(sizeof(struct node));L->next = NULL;return L; }/** Delete all nodes in a list
* 刪除表*/ void delete_list(LIST L) {position np, next;np = L;do {next = np->next;free(np);np = next;} while(next != NULL); }/** if a list only has head node, then the list is null.
* 判斷表是否為空*/ int is_null(LIST L) {return ((L->next)==NULL); }/** insert a node after position np
* 在np節點之后,插入節點*/ void insert_node(position np, int value) {position nodeAddr;nodeAddr = (position) malloc(sizeof(struct node));nodeAddr->element = value;nodeAddr->next = np->next;np->next = nodeAddr; }/** delete node at position np
* 刪除np節點*/ void delete_node(LIST L, position np) {position previous, next;next = np->next;previous = find_previous(L, np);if(previous != NULL) {previous->next = next;free(np); }else {printf("Error: np not in the list");} } /*
?* find the last node of the list
* 尋找表的最后一個節點
?*/ position find_last(LIST L) {position np;np = L;while(np->next != NULL) {np = np->next;}return np; }/** This function serves for 2 purposes:* 1. find previous node * 2. return NULL if the position isn't in the list
* 尋找npTarget節點前面的節點*/ position find_previous(LIST L, position npTarget) {position np;np = L;while (np->next != NULL) {if (np->next == npTarget) return np; np = np->next;} return NULL; }/** find the first node with specific value
* 查詢*/ position find_value(LIST L, int value) {position np;np = L;while (np->next != NULL) {np = np->next;if (np->element == value) return np;}return NULL; }
?
在main()函數中,我們初始化表,然后插入(1, 3, 5, 7, 9)。又刪除元素5。可以看到,節點零散的分布在內存中。刪除節點操作不會影響其他節點的存儲位置。
我們隨后刪除表,又重新創建表。可以看到,這次表占據內存的位置與第一次不同。
?
下面是main()函數的運行結果。
Empty List
0x154d0b0: 1
0x154d090: 3
0x154d070: 5
0x154d050: 7
0x154d030: 9
0x154d0b0: 1
0x154d090: 3
0x154d050: 7
0x154d030: 9
Empty List
0x154d070: 1
0x154d010: 3
0x154d0b0: 5
0x154d090: 7
0x154d050: 9
?
總結
表: 內存中離散分布的有序節點
插入,刪除節點
?
轉載于:https://www.cnblogs.com/xmgh/p/3784122.html
總結
- 上一篇: 避免技术文章八股化
- 下一篇: setTimeout() 实现程序每隔一