簡體   English   中英

我怎樣才能理解鏈表?

[英]How can I understand linked lists?

我試圖了解它們是如何工作的,但我遇到了很多困難。 是否有人願意直觀地解釋它們,或者提供他們認為適合剛開始使用該主題的人的資源?

所以讓我說我有這個:

struct node
{
   int nodeNum;
   nodes *next;
}

要創建“head”節點,我將執行以下操作: node *head = new node; 所以我的鏈表現在看起來像 在此輸入圖像描述 分配后:

head->nodeNum = 10;
head->next = NULL;

我們有 在此輸入圖像描述 現在,如果我想編寫一個插入節點的函數,我可以寫:

void insert(node *previousNode, int num)
{
    previousNode = new node;
    previousNode->nodeNum = num;
    previousNode->next = NULL;
}

所以,如果我這樣做,比如insert(head, 20); 我的新列表看起來像 在此輸入圖像描述

如果一切正確,我如何使用此信息從列表中搜索和/或刪除節點? 遍歷節點並不是非常直觀,如head = head->next; , 例如。 這是如何運作的?

您可以提供任何建議,使這個主題更容易理解將是偉大的。 感謝大家的幫助!

您的插入功能無法正常工作; 它只是創建一個新節點而不將其添加到列表中,並在函數返回時丟失它(給出內存泄漏):

head -> 10 -> NULL     becomes    head -> 10 -> NULL
                                  (lost)  20 -> NULL

相反,它應該將列表的舊尾部鏈接到新節點,並在舊節點之后插入新節點:

void insert(node * prev, int num) {
    node * new_node = new node;
    new_node->nodeNum = num;
    new_node->next = prev->next;  // add the old tail after the new node
    prev->next = new_node;        // add the new node after the old node
}

insert(head, 20); // insert 20 after the head
// head -> 10 -> NULL   becomes    head -> 20 -> 10 -> NULL

如何使用此信息從列表中搜索和/或刪除節點?

要進行迭代,您需要維護自己的指針,指向您正在查看的元素; head開始,然后跟隨next指針,直到它到達結尾(即next為null):

for (node * n = head; n; n = n->next) {
    if (n->nodeNum == 20) {
        std::cout << "Found node 20!\n";
        break;
    }
}

要從單鏈表中刪除節點,需要一個指向其前面節點的指針,以便更新其next指針:

void remove_next(node * prev) {
    if (prev->next) {
        node * next = prev->next->next;  // Get the tail after the removed node
        delete prev->next;
        prev->next = next;               // Add the tail after the remaining node
    }
}

remove_next(head);
// head -> 20 -> 10 -> NULL    becomes    head -> 10 -> NULL

你的問題在這里:

void insert(node *previousNode, int num)
{
previousNode = new node;
previousNode->nodeNum = num;
previousNode->next = NULL;
}

insert(head, 20);

這是代碼的作用: previousNode = new node; 創建一個指向節點的指針,並指定指向previousNode的指針。 PreviousNode以復制頭開始,它現在指向一些新東西。 您現在可以為新節點分配值。 換句話說,插入的這種實現不會插入。

你想做的更像是:

void better_insert(node *previousNode, int num)
{
    node *post_node = new node;    #create a brand new pointer to a brand new node
    post_node->nodeNum = num;      #give it a number
    post_node->next = previousNode->next; #we want previousNode to be behind new node
    previousNode->next = post_node;     
}

它的作用是:在創建一個新節點並用新指針指向它之后,我們給它一個數字。 接下來要弄清楚指針指向的位置......

讓我們假裝我們在鏈表中揮動一些節點。 所有小寫​​字母都是指針,好嗎?

a->next = b

現在說我們希望節點xa之后,並且數字為10 ...我們稱之為`better_insert(a,10)

post_node指向一個新節點(我們的節點x),並被賦予10. cool ...

我們想要:

a->next = x
x->next = b

我們有:

a->next = b
x->next = null

函數的最后兩行只是改變了東西,直到它適合賬單

所以更詳細......

我們有:

a->next = b
x->next = null

所以我們打電話:

post_node->next = previousNode->next; #we want previousNode to be behind new node

現在我們有:a-> next = b x-> next = b

現在我們打電話:

previousNode->next = post_node;

我們最終得到:

a->next = x
x->next = b

或者在其他'詞'中:

a->next = x
a->next->next = b

您需要在代碼中使用更多變量。 insert操作修改兩個節點。 需要將先前節點更改為指向新節點,並且需要創建新節點並使其指向前一節點之后的節點(可能是也可能不是NULL)。

void insert(node *previousNode, int num)
{
    node *newnode = new node;
    newnode->nodeNum = num;
    newnode->next = previousNode->next;
    previousNode->next = newnode;
}

要遍歷列表,您可以跟蹤“當前節點”,您可以從一個節點更改為下一個節點:

while (currentNode != 0) {
    do_something_with(currentNode);
    currentNode = currentNode->next;
}

當然,如果do_something_with刪除了節點,那么之后就無法從它向前邁進。 此外,要從單鏈接列表中刪除節點,您需要一個指向該節點之前的節點的指針。 因此,在這種情況下,您的循環可能會跟蹤兩個節點,當前和之前,而不是一個。

您正在使用的術語讓您感到困惑。 希望這個比喻不會讓你更加困惑。 從本質上講,想象鏈接列表就像這個可怕的門道一樣,一旦你進入一個門口,它就會在你身后關閉,你只能看到那個房間里的東西或者去另一個房間。 從這個走廊的外面,你只知道入口的位置,而不是里面的東西。

所以,從鏈表結構的外部,你只知道入口,一些指針ll_node *head; head內部是一些數據和指向鏈表中下一個節點的指針。 遍歷該鏈表非常簡單,從入口到走廊, head ,一次進入一個走廊,直到找到您正在尋找的節點。

ll_node *current_location = head;
while (current_location != NULL)
{
   // if we are at the node that you were hoping to reach, exit.
   if (current_location->nodeNum == target_data_im_looking_for)
   {
      break;
   }
   // this isn't the node you're looking for, go to the next one.
   current_location = current_location->next;
}

類似地,插入節點應該遍歷到鏈表的末尾(直到current_location->next == NULL )並將最后一個元素的下一個指針替換為您創建的新ll_node的內存位置。 我不會為你實現這個,所以你有機會學習,但這里有足夠的東西到達你想成為的地方。

通常,鏈表的節點不包含其編號。 它通常由一個Data和一個指向下一個節點的指針組成。 你也應該讓你的代碼免於拼寫錯誤。

typedef Data int;

struct node
{
   Data data; // some Data
   node *next;   // pointer to the next node
}

通常,您也不希望在指定的節點之后使用新節點,而是需要列表。 void insert(node *previousNode, int num)簽名建議您在某個指定的前一個節點之后需要新節點。

從技術上講,您可以通過三種方式將新節點添加到列表中。 到列表的開頭或結尾或中間的某個地方。 添加到開頭是最快和最簡單的。

void insert(Data num)
{
    node* tmp = new node;  //make a new node
    tmp->data = num;       //fill in data
    tmp->next = head;      //set the next element of new one to be the current head
    head = tmp;            //set new element as the head
}

這樣,您就可以在列表前放置一個新元素。 您總是從頭到尾遍歷單向鏈表。

void print_all()
{
   node* current = head;      // start at head
   while(current != NULL){    // while element exists
     cout << current->data << ' ';   //print its data
     current = current->next; //move to the next one
   }
}

當你有帶數據框的圖片和node* next箭頭時,很容易理解。

這是初學者。 您需要修改insert函數以處理列表最初為空的特殊情況。 head == NULL

另外,我強烈建議您嘗試以面向對象的方式實現它。 class List使用struct node class List

class List {
  private:
    node* head;
  public:
    List();
    void insert(data);
    void print_all();
}

嘗試實現這些功能。 根據我的經驗,當你以這種方式做事時,它有助於組織你對數據結構和容器的思考,而這更像是c ++這樣做的事情。

在上面提到的列表中,您只有很少的信息,即nodeNum。 你應該保留更多的離子信息。 例如,在具有值nodeNum = 10的節點上,您應該從該節點獲取一些其他信息。因此,當用戶調用時

node* search(node *head,int num){
      node *temp = head;//copy node reference into temp variable
      while (temp != NULL){
            if (temp->nodeNum == num){
               return temp;
            }
            temp = temp->next;
      }

} 

您可以使用節點獲取該節點中的數據

 res = search(head,10);

刪除

bool delete(node *head,int num){
      node *temp = head;//copy node reference into template
      node *prev = NULL;
      bool isDelete = false;
      while (temp != NULL){
            if (temp->nodeNum == num){
               break;
            }else
               prev = temp;
               temp = temp->next;
            }
      }
      if (temp != NULL){
          prev-> next = temp->next;//maintain list
          delete temp;
          isDelete = true;
      }
      return  isDelete;
} 

暫無
暫無

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

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