簡體   English   中英

鏈表添加到尾部,混亂

[英]linked list adding to the tail, confusion

Visual Studio 2008 C

我無法理解的這個鏈表是在if語句的else部分添加尾部。

當分配頭部和尾部時,node_temp的內存地址同時指向tail和head都指向相同的內存位置。

但是,在else部分中,頭部實際上仍然指向尾部。 有些東西我無法解釋,也不了解其他部分?

我希望有人能為我解釋得更好。

static struct convert_temp
{
    size_t cel;
    size_t fah;
    struct convert_temp *next;
} *head = NULL, *tail = NULL;

/** Add the new converted temperatures on the list */
void add(size_t cel, size_t fah)
{
    struct convert_temp *node_temp = NULL; /* contain temp data */

    node_temp = malloc(sizeof(*node_temp));

    if(node_temp == NULL)
    {
        fprintf(stderr, "Cannot allocate memory [ %s ] : [ %d ]\n",
            __FUNCTION__, __LINE__);
        exit(0);
    }

    /* Assign data */
    node_temp->cel = cel;
    node_temp->fah = fah;
    node_temp->next = NULL;

    if(head == NULL)
    {
        /* The list is at the beginning */
        head = node_temp;   /* Head is the first node = same node */
        tail = node_temp;   /* Tail is also the last node = same node */
    }
    else
    {
        /* Append to the tail */
        tail->next = node_temp;
        /* Point the tail at the end */
        tail = node_temp; 
    }
}

第一次將一個元素(讓我們稱之為A )添加到列表中時, head為null,然后通過if部分。 這意味着在添加第一個元素時, head和tail都設置為指向A

現在讓我們添加另一個元素B 這次, head不為null,因此它通過else部分,將tail設置為指向B但是將head指向A

這是預期的,你現在有head指向AA指向BB指向空(null), tail指向B

讓我們一步一步來。

Initial state:  head -+-> null
                      |
                tail -+

Insert item A:  head -+-> A ---> null
                      |
                tail -+

Insert item B:  head ---> A -+-> B ---> null
                             |
                tail --------+

Insert item C:  head ---> A ---> B -+-> C ---> null
                                    |
                tail ---------------+

您可以在每個階段(除了初始階段)看到當前尾部被設置為指向新節點(其下一個節點已經指向NULL),然后尾部指針被更新為指向新的最后一個節點。

事實上,讓我們詳細地逐行添加C(逐行),這樣你就可以看到每行代碼在做什么(為了幫助格式化,我將node_tempnode_tempnode ):

Starting state:                head ---> A -+-> B ---> null
                                            |
                               tail --------+

node = malloc(sizeof(*node));  node ---> C ----------> ?
 (allocate node C)             head ---> A -+-> B ---> null
                                            |
                               tail --------+

node->next = NULL;             node ---> C --------+
 (ignore payload cel/fah                           |
  for now since it's not       head ---> A -+-> B -+-> null
    relevant to the list                    |
               structure)      tail --------+

tail->next = node;             node ---------------+
 (first in else clause)                            |
                               head ---> A -+-> B -+-> C ---> null
                                            |
                               tail --------+

tail = node;                   node ---------------+
 (second in else clause)                           |
                               head ---> A ---> B -+-> C ---> null
                                                   |
                               tail ---------------+

然后最終node消失,因為它是一個局部變量,你有最終狀態:

                               head ---> A ---> B -+-> C ---> NULL
                                                   |
                               tail ---------------+

在單鏈表中維護tail指針的優點是避免在嘗試將項添加到最后時遍歷整個列表以找到結尾。

遍歷整個列表使得最后插入O(n)時間操作(所花費的時間取決於列表中的項目數)。 tail指針的使用使得O(1)時間操作(與列表大小無關的相同時間量)。

順便說一下,雙向鏈表對tail指針有額外的用處 - 它能夠快速開始從列表末尾到開始的遍歷,使用tail和代替headprev指針和next指針。

else-part只是更新列表的tail ,因為當你附加到鏈表時,head不會改變。

保持指向緩沖區尾部元素的指針是一種優化,因此您不必在每個追加頭上從頭部逐步執行整個列表。

並不是頭部仍指向尾巴。 頭指向尾巴。 當列表只包含一個元素時,它既是頭部也是尾部。 附加新節點后,尾指針已更新。 頭指針仍然指向第一個節點,這是正確的。

在第一次調用add時,head和tail將指向新創建的內存塊。 所有后續的add調用都會通過else部分進行調整,這只會改變尾部指針,基本上修改舊的tail-> next指向新的內存塊,然后更新tai​​l也指向這個新的內存塊。

這是一種有效的追加方式。 如果只使用了head,那么每次添加一個新的node_temp時,你必須從頭開始遍歷所有下一個指針,直到你到達之前添加的node_temp(其下一個指針為NULL),然后添加新節點。 這將是O(n)算法,而不是上面的O(1)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM