接着這兩三天的時間把模板、隊列、鏈表、二叉樹等知識又過了一遍。也親自動手寫了以上數據結構,算是把當年學數據結構時沒作完的實驗從新作了一遍,有點小小的成就感。所以寫此博文以記之,以備之後用的時候查閱。ios
模板和頭文件的知識前面兩篇博文已經大概交代了一下,之前沒學模板的時候看到這東西頭就大,如今學習了一下感受模板對於代碼的重用對提升開發效率仍是頗有幫助的。數據結構
1、鏈表的實現:ide
1 //Node.h
2 #ifndef NODE_H_H 3 #define NODE_H_H
4 template<class T>class LinkList; 5 template<class T>
6 class Node 7 { 8 friend LinkList<T>; 9 private: 10 T Data; 11 Node *Next; 12 }; 13 #endif
14 ///////////////////////////////////////////////////////
15 //LinkList.h
16 #include "Node.h"
17 #ifndef LINKLIST_H_H 18 #define LINKLIST_H_H
19 template<class T>
20 class LinkList 21 { 22 private: 23 Node<T> *head; 24 public: 25 LinkList(); 26 ~LinkList(); 27 void Insert(T data); 28 void printLinkList(); 29 Node<T> *Create(int len); 30 }; 31 #endif
32
33 template<class T>
34 LinkList<T>::LinkList() 35 { 36 head=NULL; 37 } 38
39 template<class T>
40 LinkList<T>::~LinkList() 41 { 42 Node<T> *p; 43 while(head) 44 { 45 p=head->Next; 46 delete head; 47 head=p; 48 cout<<"析構!"<<endl; 49 } 50 } 51 template <class T>
52 Node<T> *LinkList<T>::Create(int len) 53 { 54 Node<T> *p; 55 Node<T> *temp; 56 T s; 57 while(len--) 58 { 59 cout<<"輸入數據:"<<endl; 60 cin>>s; 61 temp=new Node<T>; 62 temp->Data=s; 63 temp->Next=NULL; 64 if (!head) 65 { 66 head=temp; 67 p=head; 68 } 69 else
70 { 71 p->Next=temp; 72 p=temp; 73 } 74 } 75 return head; 76 } 77 template<class T>
78 void LinkList<T>::Insert(T data) 79 { 80 Node<T> *p=head; 81 Node<T> *s=new Node<T>; 82 s->Data=data; 83 s->Next=NULL; 84 if (head==NULL) 85 { 86 head=s; 87
88 } 89 else
90 { 91 while(p->Next) 92 { 93 p=p->Next; 94 } 95 p->Next=s; 96 } 97 } 98
99 template<class T>
100 void LinkList<T>::printLinkList() 101 { 102 Node<T> *p=head; 103 while(p) 104 { 105 cout<<p->Data<<endl; 106 p=p->Next; 107
108 } 109 } 110 ///////////////////////////////////////////////////////////////////
111 //TemplateLinkList.cpp
112 #include <iostream>
113 #include<string>
114 #include "Node.h"
115 #include "LinkList.h"
116 using namespace std; 117
118 int main() 119 { 120 LinkList<char> L; 121 L.Insert('a'); 122 L.Insert('b'); 123 L.Insert('c'); 124 L.printLinkList(); 125
126 LinkList<string> s; 127 s.Insert("abcd"); 128 s.Insert("efgh"); 129 s.Insert("ijkl"); 130 s.printLinkList(); 131
132 LinkList<int> t; 133 t.Insert(1); 134 t.Insert(2); 135 t.Insert(3); 136 t.printLinkList(); 137
138 LinkList<double> d; 139 Node<double> *b; 140 b=d.Create(4); 141 d.printLinkList(); 142
143 //Node<int> n;
144 return 0; 145 }
有如下幾點須要注意的地方:函數
一、在封閉鏈表時沒有用模板時是經過檢測指定的特殊字符,好比'*'來封閉鏈表。可是用了模板以後對不一樣的數據類型,前者這種方法只對char類型是有效。因此最後改爲Node<T> *Create(int len);經過長度來封閉鏈表。再寫鏈表的時候用到兩個類Node和LinkList注意Node成員若是是private的話要在Node中聲明爲友元。還有就是在鏈表中由於要插入節點或者對節點操做,每每要先用一個或者是兩個指針指到你要操做的節點或是該節點的前繼。通常使用while(p){p=p->Next;}或是while(p->Next){p=p->Next;}具體用的時候還須要仔細考慮一下,好比要指到最後一個節點應該採用while(p->Next){p=p->Next;}。學習
二、寫析構函數的時候一開始寫的比較麻煩,最後參考別人寫了一種比較簡潔的。代碼以下:spa
1 template<class T>
2 LinkList<T>::~LinkList() 3 { 4 Node<T> *p; 5 while(head) 6 { 7 p=head->Next; 8 delete head; 9 head=p; 10 cout<<"析構!"<<endl; 11 } 12 }
三、寫鏈表主要仍是指針的操做,有的時候指來指去容易搞錯須要注意,實現的過程當中注意有頭結點和沒有頭結點的區別。3d
2、隊列的實現指針
1 //Queue.h
2 #ifndef QUQUE_H_H 3 #define QUQUE_H_H
4 template<class T>
5 class Node 6 { 7 public: 8 T Data; //節點數據
9 Node<T> *Next; //指向下一個節點
10 }; 11
12 template<class T>
13 class Queue 14 { 15 private: 16 Node<T> *Front; //隊頭,出隊
17 Node<T> *Rear; //隊尾,入隊
18 public: 19 Queue(); 20 ~Queue(); 21 void EnQueue(T data); 22 T DeQueue(); 23 bool QueueEmpty() const; 24
25 }; 26 #endif
27
28 template<class T>
29 Queue<T>::Queue() 30 { 31 Front=Rear=NULL; 32 } 33
34 template<class T>
35 Queue<T>::~Queue() 36 { 37 Node<T>*p=Front; 38 while(Front) 39 { 40 p=p->Next; 41 delete Front; 42 Front=p; 43 } 44 Front=Rear=NULL; 45 cout<<"XiGou!"<<endl; 46 } 47
48 template<class T>
49 void Queue<T>::EnQueue(T data) 50 { 51 Node<T> *p; 52 Node<T> *s=new Node<T>; 53 s->Data=data; 54 s->Next=NULL; 55 //隊列爲空
56 if (Front==NULL&&Rear==NULL) 57 { 58 Front=s; 59 Rear=s; 60 } 61 else
62 { 63 p=Front; 64 //指到隊尾
65 while (p->Next) 66 { 67 p=p->Next; 68 } 69 //入隊一個節點
70 p->Next=s; 71 Rear=s; //Rear始終指向隊尾
72 } 73 } 74
75 template<class T>
76 T Queue<T>::DeQueue() 77 { 78 Node<T> *p=Front; 79 T data=Front->Data; 80 Front=Front->Next; 81 //隊列中只有一個節點,刪除後隊列置空
82 if(NULL==Front) Rear=NULL; 83 delete p; 84 return data; 85 } 86
87 template<class T>
88 bool Queue<T>::QueueEmpty() const
89 { 90 if (Front==NULL&&Rear==NULL) 91 { 92 return true; 93 } 94 return false; 95 }
須要注意的地方:code
一、知道隊列的基本原理"先進先出",從隊頭(Front)出隊尾(Rear)進.blog
二、Front指針永遠指向隊頭,Rear永遠指向隊尾。當進行了出隊和入隊後記得更新Front和Rear指針。
三、若是自己隊列只有一個節點,出隊後隊列爲空注意此時Front=Rear=NULL,避免成爲懸浮指針。
四、注意類模板的語法。
3、二叉樹的實現
1 #include "Queue.h"
2 #ifndef BINARYTREE_H_H 3 #define BINARYTREE_H_H
4 template<class T>
5 class BinaryTree 6 { 7 private: 8 BinaryTree<T> *left; 9 BinaryTree<T> *right; 10 T data; 11 public: 12 void Create(BinaryTree<T> * &root); 13 void PreOrder(BinaryTree<T> *p); 14 void InOrder(BinaryTree<T> *p); 15 void PostOrder(BinaryTree<T> *p); 16 void CountLeaf(BinaryTree<T> *p,int &count); 17 void BinatyTreeDepth(BinaryTree<T> *p,int level,int &count); 18 void LayerOrder(BinaryTree<T> *t); 19 }; 20 #endif
21
22 template<class T>
23 void BinaryTree<T>::Create(BinaryTree<T> * &root) 24 { 25 T a; 26 cin>>a; 27 if (a!='*') 28 { 29 root=new BinaryTree; 30 root->data=a; 31 Create(root->left); 32 Create(root->right); 33 } 34 else root=NULL; 35 } 36
37 template<class T>
38 void BinaryTree<T>::PreOrder(BinaryTree<T> *p) 39 { 40 if (p!=NULL) 41 { 42 cout<<p->data<<endl; 43 PreOrder(p->left); 44 PreOrder(p->right); 45 } 46 } 47
48 template<class T>
49 void BinaryTree<T>::InOrder(BinaryTree<T> *p) 50 { 51 if (p!=NULL) 52 { 53 InOrder(p->left); 54 cout<<p->data<<endl; 55 InOrder(p->right); 56 } 57 } 58
59 template<class T>
60 void BinaryTree<T>::PostOrder(BinaryTree<T> *p) 61 { 62 if (p!=NULL) 63 { 64 PostOrder(p->left); 65 PostOrder(p->right); 66 cout<<p->data<<endl; 67 } 68 } 69
70 template<class T>
71 void BinaryTree<T>::CountLeaf(BinaryTree<T> *p,int &count) 72 { 73 if (p) 74 { 75 if (!(p->left)&&!(p->right)) 76 { 77 count++; 78 } 79 //注意這兩句話外層這個if語句大括號裏
80 CountLeaf(p->left,count); 81 CountLeaf(p->right,count); 82 } 83 } 84
85 template<class T>
86 void BinaryTree<T>::BinatyTreeDepth(BinaryTree<T> *p,int level,int &count) 87 { 88 if (p) 89 { 90 if (level>count)count=level; 91 BinatyTreeDepth(p->left,level+1,count); 92 BinatyTreeDepth(p->right,level+1,count); 93 } 94 } 95
96
97 template<class T>
98 void BinaryTree<T>::LayerOrder(BinaryTree<T> *t) 99 { 100 Queue<BinaryTree<T>*> q; 101 BinaryTree<T> *p; 102 T da; 103 q.EnQueue(t); 104 while(!q.QueueEmpty()) 105 { 106 p=q.DeQueue(); 107 da=p->data; 108 cout<<da<<endl; 109 if(p->left) 110 q.EnQueue(p->left); 111 if(p->right) 112 q.EnQueue(p->right); 113 } 114 }
須要注意的幾點地方:
一、void Create(BinaryTree<T> * &root);中&不能少。若是不要&遞歸每次生成左子樹和右子樹每次不會生成新的節點。
二、統計葉節點的思路「當一個節點的左子樹和右子樹爲空時,該節點就是葉節點」if (!(p->left)&&!(p->right)){count++; }。
三、計算樹的深度「每遞歸往下走一層,對比當前子樹深度是否大於當前記錄的值,大於就替換」
四、廣度遍歷二叉樹時須要用到隊列,隊列的元素師指向樹的指針,從根節點的指針開始入隊,每一個while()循環把當前隊頭節點的兩個節點入隊。因此循環一共循環非葉節點個數減一次,減一主要是根節點一開始就入隊了。最後隊列中就按層次的順序排列了樹的部分節點。注意不是所有節點都在隊列中,入隊和出隊是動態的過程,不是一口氣所有節點所有入隊再出隊。