資料結構面試之一——單鏈表常見操作
題註:《程式員面試寶典》有相關習題,但思路相對不清晰,排版有錯誤,本文對此參考相關書籍和自己觀點進行了重寫,供大家參考。
1.尋找鏈表元素
Step1:置尋找標記bfound=false;判斷鏈表是否為空白,是,提示“不能尋找空鏈表”;否,進入step2。
Step2:從鏈表頭開始尋找,判斷(當前點的info是否與待尋找元素值相等&&指標未指向末尾),是,“尋找結束,bfound=true”,否,繼續尋找。
Step3:判斷bfound= = true,是,“提示尋找成功”,否,“提示尋找失敗”。
/尋找單鏈表元素template<typename Type>void linkedlistType<Type>::search(const Type& searchItem){ nodeType<Type> *current; bool found = false; if(first == NULL) //1.空鏈表 { cout << "WARNING: Can not search an empty list!" << endl; return; } else { current = first; while(!found && current != NULL) { if(current->info == searchItem) { found = true; break; } else { current = current->link; } } if(found) { cout << searchItem << " was found in the List! " << endl; } else { cout << searchItem << " was not found in the List! " << endl; } }}
2.刪除鏈表元素值
Step1:置尋找標記bfound=false; 判斷鏈表是否為空白,是,提示“不能對空鏈表進行刪除操作”;否,進入step2。
Step2:判斷待刪除元素值是否與前端節點元素值相等,是,調整前端節點指標;否,進入step3。
Step3:判斷鏈表中是否存在該元素,否,“提示元素不存在”;是,進入step4。
Step4:判定要刪除元素是否與末尾節點元素值相等,是,調整末尾last指標;否,此時為中間節點,需要調整trailCurrent和Current指標的指向。
//刪除單鏈表元素template<typename Type>void linkedlistType<Type>::deleteNode(const Type& deleteItem){ nodeType<Type> *tempNode = new nodeType<Type>; nodeType<Type> *current = new nodeType<Type>; nodeType<Type> *trailCurrent = new nodeType<Type>; bool found; //鏈表為空白 case1 if(first == NULL) { cout << "Can not delete an empty List!" << endl; } else { if( first->info == deleteItem ) { //要刪除的也是第一個節點(僅一個節點,或不止一個節點) case2 tempNode = first; first = first->link; if(first == NULL) { last = NULL; } delete tempNode; } else { //先尋找,後判斷... case3 found = false; trailCurrent = first; current = first->link; while((!found) && (current != NULL)) { if(deleteItem != current->info) { trailCurrent = current; current = current->link; } else { found = true; } } if(found) { //能找到... trailCurrent ->link = current->link; if(current == last) { last = trailCurrent; //case 3a } delete current; //case 3b } //不存在該點...case4 else { cout << "The deleteItem is not Exist in the List! " << endl; } //end else }//end else }//end else }// end deleteNode
3.單鏈表逆置[迭代實現]
Step1:判斷鏈表是否為空白,是,提示“不能對空鏈表進行逆置操作“;否,進入Step2;
Step2:從第2個節點開始,依次將每個節點插入到第一個節點的前面,判斷指標是否指向了鏈表尾部,是,返回頭指標結束;否,繼續迭代後面的鏈表元素。
template<typename Type>nodeType<Type>* linkedlistType<Type>::reverseList() //逆置單鏈表{ if(first == NULL) { cout << "Can't reverse empty List!" << endl; } else { nodeType<Type>* p = first; nodeType<Type>* q = p->link; while(q != NULL) { p->link = q->link; q->link = first; first = q; q = p->link; } } return first;}
4.單鏈表排序[直接插入排序]
思路:分為以下幾種情況:
1) 單鏈表為空白;
2) 單鏈表非空,但僅含一個元素,無需排序已經有序;
3) 待插入元素小於頭結點的元素;
4) 待插入元素為前已有序的中間的元素值;
5) 待插入的元素前所有元素都比其小,直接插到末尾。
分別用lastInOrder記錄已經有序的最後一個節點,firstOutOfOrder第一個尚未排序(正待參與)排序的節點。current用於記錄迴圈的節點,trailCurrent記錄current前的節點。
template<typename Type>void linkedlistType<Type>::sortList() //單鏈表排序{ nodeType<Type>* current; nodeType<Type>* trailCurrent; nodeType<Type>* lastInOrder; nodeType<Type>* firstOutOfOrder; lastInOrder = first; //case1,表為空白. if(first == NULL) { cout << "Can't Sort of empty List!" << endl; return; } //case2,表不為空白,但表長為1,僅含1個元素. if(first->link == NULL) { cout << "The List Was Already ordered!" << endl; return; } while(lastInOrder->link != NULL) { firstOutOfOrder = lastInOrder->link; //case3,要插入的元素小於第1個元素. if(firstOutOfOrder->info < first->info) { lastInOrder->link = firstOutOfOrder->link; firstOutOfOrder->link = first; first = firstOutOfOrder; } else { trailCurrent = first; current = first->link; while(current->info < firstOutOfOrder->info) { trailCurrent = current; current = current->link; } //case4,要插入的元素在前已有序元素的中間. if(trailCurrent != lastInOrder) { lastInOrder->link = firstOutOfOrder->link; firstOutOfOrder->link = current; trailCurrent->link = firstOutOfOrder; } else { //case5,要插入的元素大於最後一個已經有序的元素. lastInOrder = lastInOrder->link; }//end else }//end else }//end while}
5.單鏈表在不知道鏈表長度的前提下求鏈表中間節點的值。
思路:分以下幾種情況:
1) 鏈表為空白;
2) 鏈表非空,但僅有一個或兩個節點;可以直接返回第一個節點的元素值。
3) 鏈表非空,但含有三個或三個以上的節點,可以通過定義兩個指標,一個指標的跳步為2次的時候,另一個指標的跳步為1次,當跳至結尾時,另一個節點恰好在中間位置。
//不知道表長的前提下求單鏈表中間元素
template<typename Type>Type linkedlistType<Type>::midValOfList() { nodeType<Type> *current; nodeType<Type> *halfCurrent; if(first == NULL) //case1,沒有節點 { cout << "鏈表為空白!" << endl; return -1; } else if(first->link == NULL || first->link->link == NULL) //case2,僅一個節點或兩個節點. { return first->info; } else //case3,含有三個或三個以上的節點. { current = first; halfCurrent = current; while(current->link != NULL) { current = current->link; if(current->link != NULL) { if(current->link != NULL) { halfCurrent = halfCurrent->link; current = current->link; }//end if } }//end while return halfCurrent->info; }//end else}
6.單鏈表建立
思路:單鏈表的建立可分為根據插入新節點的位置的不同而分為兩種,1:在鏈表末尾插入元素的建立方式;2:在鏈表前面插入元素建立鏈表的方式。
對應1末尾插入分為兩步:
Step1:如果當前鏈表為空白,則置first=last=newNode;否則,進入Step2。
Step2:插入新結點元素,修改last指標。
對於2鏈表first指標前插入:主要需要保證插入元素後,修正first節點即可。
//正向末尾插入template<typename Type>nodeType<Type>* linkedlistType<Type>::buildListForward(){ nodeType<Type> *newNode; int num; cout << " Enter a list of integer end with -999. " << endl; cin >> num; while(num != -999) { //..add newNode = new nodeType<Type>; newNode->info = num; newNode->link = NULL; if(first==NULL) { first = newNode; last = newNode; } else { last->link = newNode; last = newNode; } cin >> num; } return first;} //反向表頭插入,從前面插入...template<typename Type>nodeType<Type>* linkedlistType<Type>::buildListBackward(){ nodeType<Type> *newNode; int num; cout << " Enter a list of integer end with -999. " << endl; cin >> num; while(num != -999) { //..add newNode = new nodeType<Type>; newNode->info = num; newNode->link = first; first = newNode; cin >> num; } return first;}
7.單鏈表的測量長度
思路:鏈表的長度等效為節點個數,指標非空則迴圈判斷即可。
//求解鏈表長度template<typename Type>int linkedlistType<Type>::length(){ int count = 0; nodeType<Type> *current; current = first; while(current != NULL) { count++; current = current->link; } return count; //節點個數等效為長度.}
8.單鏈表的插入
思路:鏈表的插入也同鏈表的建立一樣分為前向、後向插入兩種形式,注意first、last指標的指向問題。
//在前面插入template<typename Type>void linkedlistType<Type>::insertFirst(const Type& newItem){ //last no use. nodeType<Type> *newNode = new nodeType<Type>; newNode->info = newItem; newNode->link = first; //在前面加入... first = newNode;} //在後面插入元素...template<typename Type>void linkedlistType<Type>::insertLast(const Type& newItem){ nodeType<Type> *newNode = new nodeType<Type>; newNode->info = newItem; newNode->link = NULL; //在後面加入... if(first == NULL) { first = newNode; last = newNode; } else { last->link = newNode; last = newNode; }}
後續陸續會有棧、隊列、二叉樹、圖、排序、尋找等的相關分析,希望大家關注!