C#刷剑指Offer | 在O(1)时间删除链表节点
【C#刷題】|?作者?/ Edison Zhou
我們來用之前學到的數據結構知識來刷《劍指Offer》的一些核心題目(精選了其中30+道題目),希望對你有幫助!本文題目為:在O(1)時間刪除鏈表節點。
1題目介紹
題目:給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點。
《劍指Offer》一書中使用的C/C++來定義節點,我們這里使用C#來定義節點:
public class Node<T> {// 數據域public T Item { get; set; }// 指針域public Node<T> Next { get; set; }public Node() {}public Node(T item) {this.Item = item;} }我們最終要實現的DeleteNode方法定義如下:
2解法1:常規思路
在單向鏈表中刪除一個結點,最常規的做法無疑是從鏈表的頭結點開始,順序遍歷查找要刪除的結點,并在鏈表中刪除該結點。這種思路由于需要順序查找,時間復雜度自然就是O(n)。
3解法2:正確思路
是不是一定需要得到被刪除的結點的前一個結點呢?答案是否定的。
我們可以很方便地得到要刪除的結點的下一個結點。因此,我們可以把下一個結點的內容復制到需要刪除的結點上覆蓋原有的內容,再把下一個結點刪除,就相當于把當前需要刪除的結點刪除了。
但是,還有兩個特殊情況需要進行考慮:
(1)如果要刪除的結點位于鏈表的尾部,那么它就沒有下一個結點:
此時我們仍然從鏈表的頭結點開始,順序遍歷得到該結點的前序結點,并完成刪除操作,這仍然屬于O(n)時間的操作。
(2)如果鏈表中只有一個結點,而我們又要刪除鏈表的頭結點(也是尾結點):
此時我們在刪除結點之后,還需要把鏈表的頭結點設置為NULL。
最后,通過綜合最壞情況(尾節點需要順序查找,1次)和最好情況(n-1次),因此平均時間復雜度為O(1):
需要注意的是:受到O(1)時間的限制,我們不得不把確保結點在鏈表中的責任推給了方法DeleteNode的調用者。
下面是DeleteNode方法的C#代碼實現:
4單元測試
老規矩,仍然需要為我們的代碼寫單元測試,這也是一個好習慣哦!
首先,為了后面測試驗證方便,這里我們先封裝一個測試輔助方法GetPrintNodes用于對比實際值與期望值是否一致:
public static string GetPrintNodes(Node<int> headNode) {if (headNode == null){return string.Empty;}StringBuilder sbNodes = new StringBuilder();while(headNode != null){sbNodes.Append(headNode.Item);headNode = headNode.Next;}return sbNodes.ToString(); }其次,測試代碼:
// 鏈表中有多個結點,刪除中間的結點 [TestMethod] public void DeleteNodeTest1() {Node<int> head1 = new Node<int>(1);Node<int> head2 = new Node<int>(2);Node<int> head3 = new Node<int>(3);Node<int> head4 = new Node<int>(4);Node<int> head5 = new Node<int>(5);head1.Next = head2;head2.Next = head3;head3.Next = head4;head4.Next = head5;Program.DeleteNode(head1, head3);Assert.AreEqual(Program.GetPrintNodes(head1),"1245"); }// 鏈表中有多個結點,刪除尾結點 [TestMethod] public void DeleteNodeTest2() {Node<int> head1 = new Node<int>(1);Node<int> head2 = new Node<int>(2);Node<int> head3 = new Node<int>(3);Node<int> head4 = new Node<int>(4);Node<int> head5 = new Node<int>(5);head1.Next = head2;head2.Next = head3;head3.Next = head4;head4.Next = head5;Program.DeleteNode(head1, head5);Assert.AreEqual(Program.GetPrintNodes(head1), "1234"); }// 鏈表中有多個結點,刪除頭結點 [TestMethod] public void DeleteNodeTest3() {Node<int> head1 = new Node<int>(1);Node<int> head2 = new Node<int>(2);Node<int> head3 = new Node<int>(3);Node<int> head4 = new Node<int>(4);Node<int> head5 = new Node<int>(5);head1.Next = head2;head2.Next = head3;head3.Next = head4;head4.Next = head5;Program.DeleteNode(head1, head1);Assert.AreEqual(Program.GetPrintNodes(head1), "2345"); }// 鏈表中只有一個結點,刪除頭結點 [TestMethod] public void DeleteNodeTest4() {Node<int> head1 = new Node<int>(1);Program.DeleteNode(head1, head1);head1 = null;Assert.AreEqual(Program.GetPrintNodes(head1), ""); }// 鏈表為空 [TestMethod] public void DeleteNodeTest5() {Program.DeleteNode(null, null);Assert.AreEqual(Program.GetPrintNodes(null), ""); }最后,測試結果如下:
代碼覆蓋率如下:
Ref參考資料
何海濤,《劍指Offer》
后臺回復:劍指offer,即可獲得pdf下載鏈接喲!
專注于開發技術與個人成長分享,
做對你有用的公眾號!
????點擊獲取文章源碼
總結
以上是生活随笔為你收集整理的C#刷剑指Offer | 在O(1)时间删除链表节点的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: TIOBE 8 月榜单:C 力压 Jav
 - 下一篇: 堪称艺术品级的应用开发框架,Abp有望超