雙向鍊錶管理程式

2021-05-03 21:48:05 字數 3363 閱讀 1283

在寫乙個小工具的時候,需要用到對ini檔案的管理。為了讓這個小工具在linux也適用,所以在寫程式的時候沒有使用mfc提供的類庫,也沒有使用windows提供的ini操作函式,直接拿標準c寫了乙個。

在操作ini的過程中,我拿兩種雙向鍊錶來描述乙個ini檔案,也就意味著,要針對每種鍊錶都寫一套插入、刪除之類的操作函式,格外麻煩。索性,就寫了乙個通用的雙向鍊錶管理程式,省的以後麻煩。

這個「通用」的雙向鍊錶管理程式的思路是:

每種雙向鍊錶的節點結構體裡,雖然有太多的不一樣,但是next和prev指標肯定是要有的,所以,就可以制定乙個只包含next和prev成員的基礎雙向鍊錶節點結構體型別,如下:

1:

struct basic_nod_t ;

這樣,只要是具備prev和next指標的節點,都可以強制轉換為這種通用型的結構。當然,前提是,乙個具體的節點結構體在定義的時候,需要讓prev和next做為結構體的第乙個和第二個成員,這種強制轉換才會有效果。比如,現在有乙個用來儲存使用者資訊的節點結構體:

1:

struct user_info_t ;

因為user_info_t結構體的前兩個成員也是prev和next指標,那麼,當嘗試把user_info_t結構體強制轉換為basic_nod_t時,basic_nod_t內的prev和next成員即為user_info_t的對應成員。

這樣一來,通用型的管理程式就有機會實現了。因為對鍊錶的插入、刪除等操作,在一般情況下,只會牽扯到對prev和next指標的修改,所以,不管具體的結構體長什麼樣子,只要你有prev和next,我就可以操作!

來個具體的**吧,拿插入節點為例:

1:

void add_node_to(void **head, void **tail, void *node, void *to, int before_or_after)

2:
13:

else

if(before_or_after == 0)

14:
27:     }
28:

else

if(before_or_after == 1)

29:
41: }

函式在傳參的時候,採用了void指標型別,因為在實際使用過程中,節點結構體的定義並不一致。

其中,函式的head和tail引數,用來表示鍊錶的頭節點和尾節點。因為在插入節點的過程中,可能會修改head和tail,所以,這裡在傳參的時候,採用的是void**這種指標的指標的形式,用來表示,head和tail這兩個指標將來是要被修改的。

在add_node_to函式內部,會首先將傳進來的引數轉換為basic_nod_t型別,此時,節點內的prev和next指標就可以被操作了。

ok,再來個刪除節點的:

1:

void del_node(void **head, void **tail, void *node)

2:
10:

if(n == *t)

11:
14:

if(n->prev != null)

15:         n->prev->next = n->next;
16:

if(n->next != null)

17:         n->next->prev = n->prev;
18: }

還有移動節點:

1:

void move_node(void **head, void **tail, void *moved, void *to, int before_or_after)

2:

最後再來個鍊錶排線的(這裡使用的是最簡單的氣泡排序):

1:

void sort_list(void **head, void **tail, cmp_func nodcmp)

2:
18:

else

19:
23:

if(nod2 == null)

24:
29:         }
30:     }
31: }

在排序的時候,由於通用管理程式並不知道排序的依據和演算法,所以,需要提供給他乙個nodcmp函式來完成兩個節點大小的計算工作。cmp_func的定義如下:

1: typedef int (*cmp_func)(void *t1, void *t2);

基本搞定,呵呵~~

使用起來也非常簡單,仍然拿那個使用者資訊鍊錶user_info_t為例:

1:

// 定義鍊錶的頭和尾指標, 初始情況下,鍊錶為空

2:

struct user_info_t *head = null;

3:

struct user_info_t *tail = null;

4:

// 首先建立乙個節點

5: user_info_t *node = (struct user_info_t *)malloc(sizeof(struct user_info_t));
6:

// 然後初始化節點的一些必要資訊

7: node->username = (char *)malloc(strlen("test") + 1);
8: strcpy(node->username, "test");
9: node->passwd = (char *)malloc(strlen("admin") + 1);
10: strcpy(node->passwd, "admin");
11:

// 然後將節點插入鍊錶中

12: add_node(&head, &tail, node);
13:

// 同樣的方法還可以插入更多的節點;

14: add_node(&head, &tail, node);
15:

// 刪除節點也同樣方便

16: del_node(&head, &tail, node);
17:

// 注意,鍊錶管理程式並不會幫助你釋放空間,所以,如果節點是在堆中分配的,那麼記得在從鍊錶中剔除節點後,將節點占用的空間釋放

18: free(node->username);
19: free(node->passwd);
20: free(node);
21: // 搞定

乙個通用的雙向鍊錶管理程式

在寫乙個小工具的時候,需要用到對ini檔案的管理。為了讓這個小工具在linux也適用,所以在寫程式的時候沒有使用mfc提供的類庫,也沒有使用windows提供的ini操作函式,直接拿標準c寫了乙個。在操作ini的過程中,我拿兩種雙向鍊錶來描述乙個ini檔案,也就意味著,要針對每種鍊錶都寫一套插入 刪...

雙向鍊錶練手程式

看了 系統程式設計師成長計畫 開始的時候,要求練習雙向鍊錶。以下為自己寫的練習程式 include includetypedef int elemtype element type typedef struct dulnode dulnode,dulinklist int m 0 about ins...

mysql 雙向鍊錶 雙向鍊錶

雙向鍊錶是鍊錶變型,相比於單鏈表導航或者是向前和向後的兩種方式。以下是重要的術語來理解雙向鍊錶的概念 link 鍊錶的每個鏈路儲存資料稱為乙個元素。linkedlist linkedlist包含連線鏈結到名為首先第乙個鏈結,並稱為最後的最後乙個鏈結 last 雙向鍊錶表示 按照如上圖中所示,以下是要...