C#實現簡單的棧和隊列


C#提供了棧和隊列,我們自己也可以嘗試簡單實現。
而且這可以作為一個很好的面試題,主要考察c#基礎、類的設計以及數據結構。根據不同的職位需求可以考察選擇不同的考察難度和角度。4年前我第一次參加面試並進現在的公司,職位基本是公司的最低崗位了。當時面的題目就是:實現一個棧。

簡單的實現如下(考慮到順序結構實現隊列比較麻煩,采用鏈式結構):
PS:感謝@LoveZmJ的提醒,下面的代碼有個bug,對Test有興趣的人可以先不要看評論,玩玩“大家來找茬”~~

 

首先是結點類的實現:

 1  // 結點類
 2     // 注意應該使用泛型
 3     public class MyNode<T>
 4     {
 5         // 存儲的數據
 6         public T Data
 7         {
 8             get { return _data; }
 9             set { _data = value; }
10         }
11 
12         // 指向下一個結點
13         public MyNode<T> next { get { return _next; } set { _next = value; } }
14 
15         //構造函數,不提供無參版本
16         public MyNode(T data)
17         {
18             _data = data;
19             _next = null;
20         }
21 
22         // 私有字段
23         private T _data;
24         private MyNode<T> _next;
25     }

然后抽象一個簡單的父類:

 1 // 為棧和隊列提取一些通用的成員,抽象出一個父類,此處用接口還是抽象函數?
 2     // 在C#中Stack和Queue繼承自兩個接口:IEnumerable<T>, ICollection
 3     // 但是作為簡單的實現(特別是作為面試題答案),還是寫成抽象類比較好,原因有二:
 4     // 1. 可以在抽象類中實現一些通用方法,子類只需要繼承就可以直接用,可以簡化代碼
 5     // 2. 抽象出來的父類,和子類Stack、Queue可以看做“is-a”的關系。
 6     // 當然也可以是非抽象的普通類,但是處於“不能實例化”的考慮,應該是抽象的
 7     // 注意使用泛型
 8     public abstract class AbstactList<T>
 9     {
10         // 頭結點,其后才是第一個結點
11         // 注意應該是protected,對外是不可見的
12         protected MyNode<T> Header { get; set; }
13         // 尾結點,即是最后一個結點
14         protected MyNode<T> Tail { get; set; }
15         // 當前結點個數,注意是只讀屬性

16         public int NoteCount { get { return _noteCount; } }
17 
18         // 構造函數,初始化頭結點和結點個數
19         public AbstactList()
20         {
21             // 注意此處default(T)的使用
22             Header = new MyNode<T>(default(T));
23             Tail = Header;
24             _noteCount = 0;
25         }
26 
27         // “出的操作”,對於棧和隊列都是一樣的,所以可以寫在父類里
28         // 注意應該從“頭”端出,時間復雜度為O(1)
29         // 如果從“尾”端出,則會造成時間復雜度為O(n)
30         protected T Out()
31         {
32             // 注意判空,只要一個條件就可以了,將所有的條件都寫在這里可以有利於在測試的時候檢測出bug
33             if (Header.next == null && _noteCount == 0 && NoteCount == 0 && IsEmpty())
34             {
35                 throw new InvalidOperationException("Is empty!");
36             }
37 
38             MyNode<T> outNode = Header.next;
39             Header.next = Header.next.next;
40             _noteCount--;
41             return outNode.Data;
42         }
43 
44         // 判空
45         public bool IsEmpty()
46         {
47             return _noteCount == 0 ? true : false;
48         }
49 
50         // 對於“出”的操作,棧和隊列是有區別的,所以申明成抽象方法
51         // 到子類中去具體實現
52         protected abstract void In(T NodeData);
53 
54         // 子類中還要用到,所以是Protected
55         protected int _noteCount;
56     }

棧的具體實現:

 1 // 棧的實現,繼承自抽象類
 2     public class MyStack<T> : AbstactList<T>
 3     {
 4         // 實現“進”的方法,在“頭”端
 5         // 由於實現抽象類方法的當前方法默認是虛的,所以無法設為private
 6         protected override void In(T NodeData)
 7         {
 8             MyNode<T> Node = new MyNode<T>(NodeData);
 9             Node.next = Header.next;
10             Header.next = Node;
11             _noteCount++;
12         }
13 
14         // 進棧,只是將操作改個名字
15         public void Push(T NodeData)
16         {
17             In(NodeData);
18         }
19 
20         // 出棧,只是將操作改個名字
21         public T Pop()
22         {
23             return Out();
24         }
25     }

隊列的實現:

 1 // 隊列的實現,繼承自抽象類
 2     public class MyQueue<T> : AbstactList<T>
 3     {
 4         // 實現“進”的方法,在“尾”端
 5         // 由於實現抽象類方法的當前方法默認是虛的,所以無法設為private
 6         protected override void In(T NodeNode)
 7         {
 8             MyNode<T> Node = new MyNode<T>(NodeNode);
 9             Tail.next = Node;
10             Tail = Node;
11             _noteCount++;
12         }
13 
14         public void EnQue(T NodeData)
15         {
16             In(NodeData);
17         }
18 
19         public T DeQue()
20         {
21             return Out();
22         }
23     }

單元測試:

對棧和隊列的單元測試
 1  [TestClass]
 2     public class UnitTest1
 3     {
 4         [TestMethod]
 5         public void StackTest()
 6         {
 7             MyStack<char> charStack = new MyStack<char>();
 8             Assert.IsTrue(charStack.IsEmpty());
 9             charStack.Push('a');
10             Assert.IsFalse(charStack.IsEmpty());
11             charStack.Push('b');
12             Assert.AreEqual(charStack.Pop(), 'b');
13             charStack.Push('c');
14             Assert.AreEqual(charStack.NoteCount,2);
15             Assert.AreEqual(charStack.Pop(), 'c');
16             Assert.AreEqual(charStack.Pop(), 'a');
17             Assert.IsTrue(charStack.IsEmpty());
18             
19             try
20             {
21                 charStack.Pop();
22             }
23             catch (Exception ex)
24             {
25                 Assert.IsInstanceOfType(ex,typeof(InvalidOperationException));
26             }
27         }
28 
29         [TestMethod]
30         public void QueueTest()
31         {
32             MyQueue<int> intQueue = new MyQueue<int>();
33             Assert.IsTrue(intQueue.IsEmpty());
34             intQueue.EnQue(1);
35             intQueue.EnQue(2);
36             Assert.AreEqual(intQueue.DeQue(), 1);
37             intQueue.EnQue(3);
38             Assert.AreEqual(intQueue.NoteCount,2);
39             Assert.AreEqual(intQueue.DeQue(), 2);
40             Assert.AreEqual(intQueue.DeQue(), 3);
41             Assert.IsTrue(intQueue.IsEmpty());
42 
43             try
44             {
45                 intQueue.DeQue();
46             }
47             catch (Exception ex)
48             {
49                 Assert.IsInstanceOfType(ex, typeof(InvalidOperationException));
50             }
51         }
52     }

后記:
作為更高難度,還可以加一個要求:實現Sort方法。由於使用的泛型,因此這應該是一個通用的排序方法,有兩種方法可以實現:接口和委托,以后再寫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM