你打什麼是簡單鏈表和一個叫做循環鏈表細化的區別。由於模糊描述了一個簡單的列表,通常分別保留附加的1或2個指針(HEAD
)或(HEAD, TAIL
),分別保存列表的開始節點(HEAD
)和當前結束節點(TAIL
)。 HEAD/TAIL
有什麼意義?
簡單的答案是雙重的。 (1)它允許在列表的開始或結束處添加節點的永久引用,以及(2)它們提供用於遍歷列表的開始和結束點。但是你必須讓他們實現一個鏈表嗎? 號
一個循環鏈表無需通過讓end->next
點first
(因而名字保留任何HEAD,TAIL
指針(S)圓形鏈表。我都用了,並迅速放棄了HEAD,TAIL
簡單列表,轉而使用圓形鏈表。爲了獲得好處,你可以添加額外的指針node->prev
並使列表成爲圓形雙鏈表它保留了訪問HEAD & TAIL
的能力節點沒有迭代。
是一個比簡單列表難以實現的循環列表 - >沒有,它只需要不同的add_node
函數。讓我們來看看。顯示簡單和圓形列表之間的關係和區別的圖幫助(如圖所示的雙鏈表):
Tail Current Head
(node->prev) node (node->next)
+------------+ +------------+ +------------+
| payload | | payload | | payload |
+------------+ +------------+ +------------+
+<------| prev |<-------| prev |<-------| prev |<------+
| +------------+ +------------+ +------------+ |
| +--->| next |------->| next |------->| next |--->+ |
| | +------------+ +------------+ +------------+ | |
| | | |
| +<--------------------<---------------------<----------------------+ |
| |
+------------------------>--------------------->------------------------>+
如果你仔細觀察,你會看到一個簡單和圓形列表中的所有實際用途都完全相同,但是,在簡單的列表中,您的必須跟蹤您的HEAD,TAIL
指針,但對於圓形列表,實施的邏輯會爲您追蹤它們。這就是區別,這就是爲什麼你的問題的答案:分配HEAD,TAIL
指針的重點?只是爲了提供插入新節點和迭代的開始和結束點。如果您在實施過程中很聰明,那麼您不必擔心分配它們,您的列表邏輯會爲您保留跟蹤。考慮到這一點,下面是一個實現循環列表的示例,無需跟蹤HEAD,TAIL
。
爲您的數據結構,你會通常有:
typedef struct list {
char *data;
struct list *prev;
struct list *next;
} list;
然後你有你的功能create node
和insert node
末。 注:的insert node
函數調用create node
,但都可以在insert node
如果你選擇:
list *create_node (char *str) {
list *node = NULL;
node = malloc (sizeof (struct list)); /* allocate memory for new node */
node-> data = strdup (str); /* allocate and save payload data */
return node; /* return node poiter to add to list */
}
list *insert_at_end (list **ll, char *str) {
/* create the node and allocate memory for node and payload
if no list, then create and assign as list address
else, insert new node at end of list */
list *node = NULL; // create a new node pointer for list
node = create_node (str); // allocate new node and fill payload
/* now just Wire/Rewire list pointers to accept node */
if (!*ll) { // this is the first node
node-> next = node; // circular linked-list
node-> prev = node; // set next, prev = node
*list = node; // set *list = node (adding node to list)
} else { // add - insert new node at end
node->next = *ll; // set node->next to list
node->prev = (*ll)->prev; // set node->prev to list->prev
node-> prev-> next = node; // set (old end)->next to this node
(*ll)-> prev = node; // set list->prev to node
}
return node; // return pointer to current node for convenience
// (immediate reference) and to test success
}
在你main()
完成後,你只需類似於:
list *mylist = NULL;
int i = 0;
// add data to your list (example using argv entries)
for (i = 0; i < argc; i++)
insert_at_end (&mylist, argv[i]);
...
希望這有助於你的理解。無論您使用的是簡單或圓形,單或雙鏈表,只要確保你明白爲什麼每個分配所取得的邏輯和。這只是一個指針遊戲。它們都是簡單的數據結構,但它們確實需要一個陡峭而短暫的學習曲線。花一些時間來學習一下,從那時起他們就會很好地爲你服務。網上有許多教程和howto,用於簡單和循環列表。現在知道不同之處,它會讓你更容易找到你所需要的東西。
從技術上講,這是一個列表的尾部(而不是插入)的附加。 list-> foot-> next = new將最後一個節點的下一個指針設置爲new,然後list-> foot = new將腳指針設置爲new。 – rcgldr 2014-09-19 00:45:36