1. 程式人生 > 實用技巧 >手寫連結串列二叉樹佇列

手寫連結串列二叉樹佇列

// 反轉單鏈表  
ListNode * ReverseList(ListNode * pHead)  
{  
        // 如果連結串列為空或只有一個結點,無需反轉,直接返回原連結串列頭指標  
    if(pHead == NULL || pHead->next == NULL)    
        return pHead;  
  
    ListNode * pReversedHead = NULL; // 反轉後的新連結串列頭指標,初始為NULL  
    ListNode * pCurrent = pHead;  
    while(pCurrent != NULL)  
    {  
        ListNode 
* pTemp = pCurrent; pCurrent = pCurrent->next; pTemp->next = pReversedHead; // 將當前結點摘下,插入新連結串列的最前端 pReversedHead = pTemp; } return pReversedHead; }

查詢單鏈表中間節點

設定兩個指標,只不過這裡是,兩個指標同時向前走,前面的指標每次走兩步,後面的指標每次走一步,前面的指標走到最後一個結點時,後面的指標所指結點就是中間結點,即第(n/2+1)個結點。注意連結串列為空,連結串列結點個數為1和2的情況。時間複雜度O(n)。參考程式碼如下:

// 獲取單鏈表中間結點,若連結串列長度為n(n>0),則返回第n/2+1個結點  
ListNode * GetMiddleNode(ListNode * pHead)  
{  
    if(pHead == NULL || pHead->next == NULL) // 連結串列為空或只有一個結點,返回頭指標  
        return pHead;  
  
    ListNode * pA = pHead;  
    ListNode * pB = pHead;  
    while(pA->next != NULL) // 前面指標每次走兩步,直到指向最後一個結點,後面指標每次走一步  
{ pA = pA->next; pB = pB->next; if(pA->next != NULL) pA = pA->next; } return pB; // 後面的指標所指結點即為中間結點 }

合併兩個有序的單鏈表使之有序

ListNode * MergeSortedList(ListNode * pHead1, ListNode * pHead2)  
{  
    if(pHead1 == NULL)  
        return pHead2;  
    if(pHead2 == NULL)  
        return pHead1;  
    ListNode * pHeadMerged = NULL;  
    if(pHead1->data < pHead2->data)  
    {  
        pHeadMerged = pHead1;  
        pHeadMerged->next = MergeSortedList(pHead1->next, pHead2);  
    }  
    else  
    {  
        pHeadMerged = pHead2;  
        pHeadMerged->next = MergeSortedList(pHead1, pHead2->next);  
    }  
    return pHeadMerged;  
}  

單鏈表第一個公共節點

ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2)
 {        
         ListNode *p1 = pHead1;
        
         ListNode *p2 = pHead2;
        
       while(p1!=p2)
       {
            
            p1 = (p1==NULL ? pHead2 : p1->next);
            
            p2 = (p2==NULL ? pHead1 : p2->next);
        }
        
         return p1;
}

更多單鏈表請移步:https://blog.csdn.net/u014800094/article/details/69523799

==========================================

樹的廣度優先遍歷。BFS,也就是層次遍歷,相當於前序。需要藉助一個佇列,現將二叉樹的根節點入隊,然後出隊,訪問該節點,如果它有左子樹,則將左子樹根節點入隊;如果有右子樹,則將右子樹根節點入隊。然後出隊,對出隊節點訪問,如此反覆,直到佇列為空。

void LevelOrder(BiTree root)
{
  InitQueue(Q);        //初始化佇列
 
  BiTree p;
  EnQueue(Q,root);      //將根節點入隊
  while(!IsEmpty(Q))     //佇列不空迴圈
  {
    DeQueue(Q,p);     //訪問p所指向節點
    visit(p);
    if(p->lchild != NULL)
       EnQueue(Q,p->lchild);     //左子樹不空則左子樹入隊
    if(p->rchild != NULL)
       EnQueue(Q,p->rchild);
   }
}

樹的深度優先遍歷。DFS,遍歷了根節點後,就開始遍歷左子樹,所以右子樹肯定最後遍歷。我們利用棧的性質,所以先將右子樹壓棧,然後在對左子樹壓棧。此時,左子樹節點是在top上的,所以可以先去遍歷左子樹。

voidDepthFirstTravel(BiTree*root)
{
stack<BiTree*>s;
  s.push(root);      //根節點入棧
while(!s.empty())
{
root=s.top();        //讀取根節點
      s.pop();            //根節點出棧

if(root->rchild!=NULL)
{
s.push(root->rchild);      //先右
}
if(root->lchild!=NULL)
{
s.push(root->lchild);      //再左
}

}
} 

棧空: s.top == -1

棧滿: s.top == MaxSize -1

入棧: s.data[++s.top] = x ; //指標先加1,再入棧

出棧: x = s.data[s.top--]; //先出棧,指標再減1

隊空:Q.front == Q.rear

隊滿:(Q.rear+1)%MaxSize == Q.front

佇列中元素:(Q.rear - Q.front + Maxsize)%MaxSize

==========================
兩個棧實現佇列

12

void push(int node)
 {
       stack1.push(node);
 }
int pop()
 {
        int a;
        if(stack2.empty())
       {
            while(!stack1.empty())
            {
                a=stack1.top();
                stack2.push(a);
                stack1.pop();
            }
        }
        a=stack2.top();
        stack2.pop();
        return a;
         
 }

<分析>:

入隊:將元素進棧A

出隊:判斷棧B是否為空,如果為空,則將棧A中所有元素pop,並push進棧B,棧B出棧;

如果不為空,棧B直接出棧。

同理:

用兩個佇列實現一個棧的功能

<分析>:

入棧:將元素進佇列A

出棧:判斷佇列A中元素的個數是否為1,如果等於1,則出佇列,否則將佇列A中的元素 以此出佇列並放入佇列B,直到佇列A中的元素留下一個,然後佇列A出佇列,再把 佇列B中的元素出佇列以此放入佇列A中。