本小題請務必重視,綜合了各種鍊錶操作(各種考試考題),可以做成乙個比較完整的工程,請設計測試程式進行測試,務必自己編寫**。
1.針對帶表頭結點的單鏈表,試編寫下列函式。
(1) 建立函式create:根據一維陣列a[n]建立乙個單鏈表,使單鏈表中各元素的次序與a[n]中各元素的次序相同,要求該程式的時間複雜性為o(n)。
(2) 定位函式locate:在單鏈表中尋找第i個結點。若找到,則函式返回第i個結點的位址;若找不到,則函式返回null。
(3) 求最大值函式max:通過一趟遍歷在單鏈表中確定值最大的結點。
(4) 統計函式number:統計單鏈表中具有給定值x的所有元素。
(5) 倒置函式reverse: 倒置線性表中元素的順序。
(6) 整理函式tidyup:在非遞減有序的單鏈表中刪除值相同的多餘結點。
(7) 合併兩個鍊錶mergelists: 輸入的鍊錶按照其元素順序從小到大排序,輸出的鍊錶也要求按照元素的大小順序排列。
注:認真完成上面的題目可以快速入門鍊錶操作。本文給出的**示例是博主的課堂練習,只考慮了相關功能的實現,有些細節的處理不夠完善,不建議讀者直接複製使用,希望讀者閱讀過程中思考這些問題。
先來分析一下這個題目涉及的鍊錶操作技術:
create/mergelists((末尾)插入
)
locate/max/number(遍歷
)
reverse
tidyup(刪除
)
可以看出,這七個題涉及的操作無非是線性表的增刪查改
,附上**:
#include
using namespace std;
template class link
link
(link* nextval =
null)}
;template
void
lprint
(link
*l) cout <<
">"
<< endl;
}template
link
*create
(e *a,
int n)
return head;
}template
link
*locate
(link
*head,
const
int index)
return
null;}
template
link
*max
(link
*head)
return temp;
}template
intnumber
(link
*head,
const e& value)
return num;
}template
void
reverse
(link
*head)
curr->next = pre;
head->next = curr;}}
template
void
tidyup
(link
*head)}}
template
void
listmerge
(link
*head1, link
* head2, link
*head3)
else
curr3 = curr3->next;}if
(curr1 !=
null
) curr3->next = curr1;
if(curr2 !=
null
) curr3->next = curr2;
}int
main()
;int b=
;int c=
; link<
int>
*p =
create
(a,10);
lprint
(p);
link<
int>
*p1 =
locate
(p,11);
if(p1 !=
null
) cout << p1->element << endl;
link<
int>
*p2 =
max(p);if
(p2 !=
null
) cout << p2->element << endl;
cout <<
"the total number of 32 is "
<<
number
(p,32
)<< endl;
reverse
(p);
lprint
(p);
tidyup
(p);
lprint
(p);
p =create
(b,10);
p1 =
create
(c,10);
link<
int>
*p5 = new link<
int>
;listmerge
(p, p1, p5)
;lprint
(p5)
;system
("pause");
}
注:這裡不得不提一下,第6題讀者只需將它當做當做remove函式練習即可,它並不能真正意義上實現tidyup,只是本示例**為了達到這種效果,故意湊了乙個陣列。
實現鍊錶倒置的思路很簡單,只需將當前結點curr
的next指標修改為指向當前結點的前乙個結點
即可。
由於單鏈表每個結點只能儲存下乙個結點的位址,而不知道上乙個結點的位址,所以我們需要乙個指標pre
儲存當前結點前乙個指標的位址。
但是只用兩個指標是無法完成整個鍊錶的倒置的,當我們將curr->next
修改為pre
後,我們就丟失了原來curr->next
中儲存的當前結點的下乙個結點
的位址,這樣就無法遍歷後面的鍊錶了。
所以在修改curr->next
之前,我們需要使用post
指標將當前結點的下乙個結點的位址儲存下來。當完成curr->next
指標的修改後,我們就將當前位置向後移動乙個結點,即將curr
指標指向post
。相應的依次維護pre
和post
指標完成鍊錶的遍歷。
博主比較懶,不想繪圖,就在網上找了乙個鍊錶轉置操作的**。
//鍊錶轉置
template
void
reverse
(link
*head)
curr->next = pre;
head->next = curr;
}}
下面我們來看mergelists函式,有點演算法基礎的讀者可以一眼看出,這個函式就是歸併排序(mergesort)的合併操作。具體思路是:對於兩個有序
的線性表a和b,每次將a和b中最小的元素從原表中『刪除』,放入空線性表c中。因為a和b原先就是有序遞增的,a和b中的第乙個元素
分別是a和b表中的最小值,所以找a和b中所有元素的最小值就可以轉化為比較a和b表中第乙個元素的大小
,較小的那乙個即為所有元素的最小值。重複上述過程直到a或b中有乙個表為空
,此時,還未空的那乙個表的剩餘元素均大於表c中的元素且是有序的,我們只要將這些元素全部複製到表c中即可。
template
void
listmerge
(link
*head1, link
* head2, link
*head3)
else
curr3 = curr3->next;}if
(curr1 !=
null
)//由於是鍊錶,我們只需將指標指向修改一下即完成'元素複製'
curr3->next = curr1;
if(curr2 !=
null
) curr3->next = curr2;
}
同樣,附上歸併排序**。
ps:如果讀者對於線性表adt以及c++模板不熟悉的可以參考博主的另一篇博文
線性表(一) 從線性表adt到鍊錶。裡面還有鍊錶insert操作的**。
鍊錶操作練習
這裡來總結一下覺得比較有思想的題啪 160.相交鍊錶 這裡的想法是a b與b a遍歷的時間是一樣的,就是說從a鍊錶開始遍歷接著從b鍊錶開始遍歷與先遍歷b在遍歷a同時結束。public class solution pa pa.next pb pb.next return ans 206.反轉鍊錶 這...
鍊錶常見操作練習
鍊錶是乙個很重要的資料結構,一直沒有好好的寫過練習,這次放假,好好練習一下。1 定義鍊錶節點 include include include typedef struct int node node 2 合併兩個有序鍊錶 版本1 node merge node p,node q else while...
棧的操作練習(鍊錶)
用鍊錶來模擬棧,節點需要乙個指向前乙個節點的pre域和資料域 棧只需要乙個棧頂即可 public class nodestack 判斷棧為空的操作就是判斷棧頂是否為null 前面初始化的棧頂就是為null 判斷是否為空 鍊錶入棧就是將入棧的節點pre域指向當前的棧頂,然後再將棧頂移到新壓入棧中的節點...