面試時面試官要求手寫雙向鏈表的 刪除操作,當時沒有考慮到邊界條件,導致被刷;
現在 列舉下代碼以及優化,作為事后反思:
C 版本:
雙向鏈表的結構定義
typedefstruct doubleLink { int data; struct doubleLink *prior; struct doubleLink *suffix; }DOUBLE_LINK;
創建一個雙向鏈表
/*創建一個雙鏈表*/ DOUBLE_LINK *createDoubleLink() { DOUBLE_LINK *head = NULL; head =(DOUBLE_LINK*)malloc(sizeof*head); head->prior = NULL; head->suffix = NULL; return head; }
插入函數
/*插入節點*/ bool insertNode(DOUBLE_LINK*head,int data) { if(head == NULL) returnfalse; DOUBLE_LINK *currNodep = NULL; DOUBLE_LINK *nextp = NULL; DOUBLE_LINK *newNodep = NULL; for(currNodep = head;(nextp = currNodep->suffix)!= NULL; currNodep = nextp) { if(nextp->data == data) returnfalse; if(nextp->data > data) break; } newNodep =(DOUBLE_LINK*)malloc(sizeof*newNodep); if(newNodep == NULL) returnfalse; newNodep->data = data; #if 1 /*需要插入雙向鏈表時,遍歷到需要插入的位置,開始對待插入的節點,前驅指針和后驅指針賦值, 后驅指針固定指向下一個節點指針,前驅需要區分 前指針是否是 頭節點。 再對 當前節點的前驅指針賦值,需要區分待插入的點是不是 尾節點*/ //1.當前節點的后驅指針 currNodep->suffix = newNodep; //2.新節點的前驅指針 if(currNodep == head) newNodep->prior = NULL; else newNodep->prior = currNodep; //3.新節點的后驅指針 newNodep->suffix = nextp; //4.下一個節點的前驅指針 if(nextp == NULL)//到了尾節點處,則將頭節點的前驅指向該尾節點,這是雙向鏈表的結構精髓所在 head->prior = newNodep; else nextp->prior = newNodep; #else if(nextp != NULL) { //one not in the tail newNodep->suffix = nextp; currNodep->suffix = newNodep; if(currNodep != head)// not the head { newNodep->prior = currNodep; } else// currnode is head { newNodep->prior = NULL; } nextp->prior = newNodep; } else { //in the tail currNodep->suffix = newNodep; if(currNodep != head)//not the head { newNodep->prior = currNodep; } else//is the head { head->prior = newNodep; newNodep->prior = NULL; } newNodep->suffix = NULL; } #endif returntrue; }
刪除某個節點
/*刪除某個節點*/ bool deleteNode(DOUBLE_LINK *head, DOUBLE_LINK *item) { _ASSERT(head != NULL); _ASSERT(item != NULL); DOUBLE_LINK *currentNodep = NULL; DOUBLE_LINK *nextp = NULL; for(currentNodep = head;(nextp = currentNodep->suffix)!= NULL; currentNodep = nextp) { if(nextp == item) { /*當前節點為頭結點時,這一點很重要*/ if(currentNodep == head)// the head { currentNodep->prior = NULL; currentNodep->suffix = nextp->suffix; free(nextp); nextp = NULL; break; } //最后一個節點時 elseif(nextp->suffix == NULL)// the tail { currentNodep->suffix = NULL; free(nextp); nextp = NULL; break; } else// the mid { DOUBLE_LINK *tmp = nextp->suffix; currentNodep->suffix = nextp->suffix; nextp->prior = currentNodep; free(nextp); nextp = tmp; } } } returntrue; }
刪除節點函數優化
bool deleteNode_opt(DOUBLE_LINK *head, DOUBLE_LINK *item) { _ASSERT(head != NULL); _ASSERT(item != NULL); //要刪除第一個節點 if(item == head->suffix) { head->suffix = item->suffix; item->suffix->prior = NULL; } //要刪除最后一個節點 elseif(item == head->prior) { head->prior = item->prior; item->prior->suffix = NULL; } else { item->prior->suffix = item->suffix; item->suffix->prior = item->prior; } free(item); item = NULL; returntrue; }
打印函數
void printAllNode(DOUBLE_LINK *head) { _ASSERT(head != NULL); DOUBLE_LINK *currentNodep = NULL; DOUBLE_LINK *nextNodep = NULL; std::cout <<"Node data is: "; for(currentNodep = head;(nextNodep = currentNodep->suffix)!= NULL; currentNodep = nextNodep) { std::cout << nextNodep->data<<" "; } std::cout << std::endl; }