C++:鏈表

鏈表簡介

鏈表是一種動態數據結構,無需知道鏈表的長度,創建鏈表時不分配內存,每當插入一個節點,需要爲新節點分配一次內存,然後調整指針的指向,使得新節點被鏈接到鏈表中。
節點定義:

Struct ListNode
{
    Int m_nValue;
    ListNode* m_pNext;
};

鏈表操作

注意!!!
1.注意保存頭結點。另新建一個節點來進行數據操作。
2.新建鏈表時,頭結點不存放數據(或存放無意義數據),這種用法經常用到。
3.不使用返回值傳遞而使用參數傳遞時,注意函數內指針的改變不影響函數外的指針,所以參數類型爲指向指針的指針或指向引用的指針。
4.在需要對鏈表進行修改時(包括,添加,刪除等操作),需要對指針進行修改,此時頭結點要單獨拿出來操作(不能使用臨時節點對頭結點進行操作),所以接下來的遍歷對象使用的是ListNode->next;

1.創建節點

ListNode* p = new ListNode();
P->m_nValue = 0;
P->m_pNext = NULL;

2.創建鏈表

3.遍歷鏈表

void travelList(node* pHead)
{
    ListNode* pNode = pHead;
    If(pHead == NULL){ Return;}
    While(pNode != Null)
    pNode = pNode->m_pNext;
}

鏈表應用

1.添加節點(使用返回值)

ListNode* addNode(ListNode*head ,int addValue)  
{  
     ListNode* newNode=new node();  
     newNode->next=NULL;  
     newNode->value=addValue;  
     ListNode* p=new node();  
     p=head; //list的頭結點  
     if(head==NULL)  {  
       head=newNode; //新節點爲鏈表頭節點  
     }else  {  
        while(p->next!=NULL)//找到尾節點  
            p=p->next;  
        p->next=newNode; //在尾節點後面加入新節點  
     }  
     return head;  
} 

添加節點(使用參數傳遞)
使用參數傳遞時,注意函數內指針的改變不影響函數外的指針,所以參數類型爲指向指針的指針或指向引用的指針。

Void addNode(ListNode** head ,int addValue)  
{  
     ListNode* newNode=new node();  
     newNode->next=NULL;  
     newNode->value=addValue;  

     ListNode* p=new node();  
     p= *head; //list的頭結點  
     if(*head==NULL)  {  
       *head=newNode; //新節點爲鏈表頭節點  
     }else {  
        while(p->next!=NULL)//找到尾節點  
            p=p->next;  
        p->next=newNode; //在尾節點後面加入新節點  
     }  
} 

2.刪除節點

ListNode*  removeNode(ListNode *head, int value)
{
    If(head == NULL){
        Return;
    }
    ListNode *p = head;
    If(head->value = value){
        Head=head->next;
    }Else{
        While((p->next!=NULL)&&(p->next->value!=value)){
            P = p->next;
        }
        If((p->next!=NULL)&&(p->next->value==value)){
            P->next = p->next->next;
        }
    }
    Return head;
}

3.從尾到頭打印(使用堆棧)

Void travleList(ListNode *head)
{
    Std::stack<ListNode *> nodes;
    ListNode *p = head;
    While(p !=  NULL){
        Nodes.push(p);
        P=p->next;
    }

    While(!nodes.empty()){
        P = nodes.top();
        Printf(“%d\t”, p->value);
        Nodes.pop;
    }
}

4. 得到鏈表的倒數第K個節點
最容易想到的當然是先遍歷一次鏈表,得到鏈表的長度n,然後得到鏈表的n-k+1個節點。需要遍歷鏈表兩次,當遇到這種情況,需要考慮只遍歷一次能不能實現。
使用兩個指針構成長度爲K的窗口,進行遍歷。

ListNode * FindTailK(ListNode *head, unsigned int k)
{
    If((head == NULL)||(k=0)){
        Return NULL;
    }
    ListNode *pStart = head;
    ListNode *pEnd = head;
    For(unsigned int i=0; i<k; i++){
        If(pEnd->next == NULL){ Return NULL; }
        pEnd = pEnd->next;
    }
    While(pEnd->next != NULL){
        pEnd = pEnd->next;
        pStart=pStart->next;
    }
    Return pStart;
}

5.反轉鏈表
爲了保證節點在改變指針指向之後依然可以遍歷接下來的節點,需要定義三個指針,分別指向當前節點,前一個節點和後一個節點。
這裏寫圖片描述
問題出現了,cur->next 在執行的過程中有修改,所以在迭代的過程中不能使用,需要引入一個臨時變量在cur->next 修改之前進行保存就可以了。

ListNode *ReverseList(ListNode *head)
{
    ListNode*  CurNode = head;
    ListNode*  PreNOde = NULL;
    ListNode*  NextNode = NULL;
    ListNode*  ReturnNode = NULL:

    While(CurNode != NULL){
        NextNode = CurNode->Next;
        If(NextNode == NULL){
            ReturnNode = CurNode;
        }
    CurNode->next=PreNode;
    preNode = CurNode;
    CurNode = NextNode;
    }
    Return ReturnNode;
}

6.鏈表分割
鏈表的分割問題,是先分割,然後再合併。
例如,給定一個鏈表和一個數字x,將小於x的位於鏈表的前面,大於等於x的位於鏈表的後面。

ListNode *Partition(ListNode* head, int x)
{
    ListNode left(-1);
    ListNode Right(-1);
    ListNode *Left_cur = &Left;
    ListNode *Right_cur=&Right;
    ListNode *Cur = head;

    While(Cur!=NULL){
        if(Cur->value<x){
            Left_cur->next = cur;
            Left_cur = Left_cur->next;
    }
    Else{
        Right_cur->next = cur;
        Right_cur = Right_cur->next;
    }
        Cur = Cur->next;
    }
    Left_cur->next = Right->next;
    Ritht_next = null;
    Return left;
}

7除去有序鏈表中重複的內容,只留下一個
在鏈表中去掉節點的方式是將next指向next->next

    ListNode* deleteDuplicates(ListNode* head) {
        if (head == nullptr) return nullptr;
        ListNode *cur = head;
        ListNode *next=head->next;
        while(cur->next!=NULL)
        {
            if (cur->val == next->val) {
                cur->next = next->next;
            } else {
                cur = cur->next;
            }
            next = cur->next;
        }
        return head;
}

8兩個數相加

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode sum(-1);
        ListNode *Cur = &sum;
        int flag = 0;   
        int value = 0, a=0, b=0;
        while((l1 != NULL)||(l2!= NULL))
        {       
            a = l1 != NULL ? l1->val   : 0;
            b = l2 != NULL ? l2->val  : 0;
            value = (a+b+flag)%10;
            flag =  (a+b+flag)/10; 
            Cur->next = new ListNode(value);
            l1 = l1 != NULL ? l1->next : NULL;
            l2 = l2 != NULL ? l2->next : NULL;
            Cur = Cur->next;
        }
        if(flag > 0) 
        {
            Cur->next = new ListNode(flag);
        }
        return sum.next;
}

9.每相鄰兩個節點交換順序

這裏寫圖片描述
利用上一步的cur進行迭代。

ListNode* swapPairs(ListNode* head) {
    if (head == nullptr || head->next == nullptr) return head;
    ListNode result(-1);
    result.next = head;

    ListNode *pre = &result;
    ListNode *cur = pre->next;
    ListNode *next = cur->next;
    while(next != NULL)
    {
       pre->next = next;
       cur->next = next->next;
       next->next = cur; 

       pre = cur;
       cur = cur->next;
       next = cur ? cur->next : NULL;
    }
    return result.next;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章