手寫連結串列二叉樹佇列
// 反轉單鏈表 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中。