代碼的魯棒性
魯棒性是指程式能夠判斷輸入是否合乎規範要求,并對不符合要求的輸入予以合理的處理。
提高代碼魯棒性的有效途徑,進行防禦性程式設計。預見在什麼地方可能出現問題,并在這些可能出現的問題制定處理方式。
面試題22:在連結清單中倒數第k個節點
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
周遊一遍 實作 找到倒數第k個節點,設定兩個指針,第一個指針走k-1步停下,第二個指針從頭指針開始周遊,
ListNode* FindKthToTail(ListNode* pListHead,unsigned int k)
{
if(ListHead == nullptr||k==0)
return nullptr;
ListNode *pAhead = pListHead;
ListNode *pBehind = nullptr;
for(unsigned int i =0;i<k;++i)
{
if(pAhead->m_pNext!= nullptr)
pAhead = pAhead->m_pNext;
else
{
return nullptr;
}
}
pBehind = pListHead;
while(pAhead->m_pNext != nullptr)
{
pAhead = pAhead->m_pNext;
pBhind = pBehind->m_pNext;
}
return pBehind;
}
代碼不夠魯棒
(1) 輸入pListNode 為空指針,由于代碼會試圖通路空指針指向的記憶體,進而造成程式崩潰
2)輸入的以pListHead 為節點的連結清單的節點數少于k,由于在for循環中會在連結清單上向前走k-1步,仍然會由于空指針而造成程式崩潰
3)輸入參數k為0。
面試題23:連結清單中環的入口節點
如果一個連結清單中包含環,如何找出環的入口節點?
ListNode* MeetingNode(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode* pSlow = pHead->m+pNext;
if(pSlow == nullptr)
return nullptr;
ListNode* pFast = pSlow->m_pNext;
while(pFast!= nullptr&&pSlow!= nullptr)
{
if(pFast == pSlow)
return pFast;
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if(pFast != nullptr)
pFast = pFast->m_pNext;
}
return nullptr;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode(Node* meetingNode == MeetingNode(pHead));
if(meetingNode == nullptr)
return nullptr;
int nodesInLoop =1;
ListNode*pNode1 = meetingNode;
while(pNode1->m_pNext!= meetingNode)
{
pNode1 = pNode1->m_pNext;
++nodesInLoop;
}
pNode1 = pHead;
for(int i =0;i<nodesInLoop;++i)
pNode1 = pNode1->m_pNext;
ListNode* pNode2 = pHead;
while(pNode1 != pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}
反轉連結清單
定義一個函數,輸入一個連結清單的頭節點,反轉該連結清單并輸出反轉後連結清單的頭節點。連結清單的節點定義如下:
struct ListNode
{
int m_nKey;
ListNode *m_pNext;
}
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReversedHead =nullptr;
ListNode* pNode = pHead;
ListNode* pPrev = nullptr;
while(pNode != nullptr)
{
ListNode* pNext = pNode->m_pNext;
if(pNext == nullptr)
pResversedHead = pNode;
pNode->m_pNext = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
為了避免連結清單在節點i處斷裂,我們需要調整節點i的m_pNext之前,把節點j儲存下來。
面試題 :合并兩個連結清單
輸入兩個遞增排序的連結清單,,合并這兩個連結清單并使新連結清單中的節點仍然是遞增排序的。
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
}
ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
if(pHead1 == nullptr)
return pHead2;
else if(pHead2 == nullptr)
return pHead1;
ListNode* pMergeHead = nullptr;
if(pHead1->m_nValue<pHead2->m_nValue)
{
pMergeHead = pHead1;
pMergeHead->m_pNext = Merge(pHead1->m_pNext,pHead2)
}
else
{
pMergeHead = pHead2;
pMergeHead->m_pNext = Merge(pHead1,pHead2->m_pNext);
}
return pMergeHead;
}
考察分析問題的能力,需要大量指針操作,分析哪些情況會引入空指針,并考慮怎麼處理這些空指針。
樹的子結構
輸入兩顆二叉樹A和B,判斷B是不是A的子結構,
struct BinaryTreeNode
{
double m_dbValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
bool HasSubtrr(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
bool result = false;
if(pRoot1 != nullptr &&pRoot2!= nullptr)
{
if(Equal(pRoot1->m_dbVaule,pRoot2->m_dbValue))
result = DoesTree1HaveTree2(pRoot1,pRoot2);
if(!result)
rsult = HasSubtree(pRoot1->m_pLeft,pRoot2);
if(!result)
result = HasSubtree(pRoot1->m_pRight,pRoot2);
}
return result;
}
bool DoseTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
if(pRoot2 == nullptr)
return true;
if(pRoot1 == nullptr)
return false;
if(!Equal(pRoot1->m_dbValue,pRoot2->m_dbValue))
return false;
return DoseTree1HaveTree2(pRoot1->m_pLeft,pRoot2->m_pLeft)
&&DoseTree1HaveTree2(pRoot1->m_pRight,pRoot2->m_pRight);
}
bool Equal(double num1,double num2)
{
if((num1-num2>-0.00000001)&&(num1-num2<0.00000001))
return true;
else
return false;
}
和連結清單相比,樹中的指針操作也更多也更複雜,