这是一个系列的文章,主要目的是让初学者掌握链表的实现方法,并且从C过渡到C++。
作者:重庆工程职业技术学院 万青
第3篇文章中,add、insert方法的参数变成了指针,假设所有类的基类是Object,那么该指针是可以指向任何对象的。也就是说,链表节点可以容纳任意类型的数据(当然只是存了一个首地址)。
不过更彻底的解决办法是用模板类:
1 #include<iostream> 2 using namespace std; 3 template<class T> 4 class CNode //节点类 5 { 6 public: 7 T data; 8 CNode *next; 9 CNode(T d) //构造函数 10 { 11 data=d; 12 next=NULL; 13 } 14 }; 15 template<class T> 16 class CList //链表类 17 { 18 private: 19 CNode<T> *head,*tail; //头、尾节点对象指针 20 int length; //节点总数 21 public: 22 CList(); //构造函数(创建链表对象,并创建头节点,初始化头、尾指针等) 23 void add(T data); //添加值为data的节点到链表末尾 24 int insert(T data,int idx); //将数据data插入到链表的idx位置之后 25 int del(int idx); //删除链表中的第idx个节点(idx从1开始计) 26 CNode<T> * getPointerByIndex(int idx);//获取第idx个节点的对象指针(idx从1开始计) 27 T* toArray(); //显示(遍历)链表的所有节点 28 int getLength() 29 { 30 return length; 31 } 32 ~CList(); //析构函数(清除链表中的所有节点对象) 33 }; 34 35 template<class T> 36 CList<T>::CList() 37 { 38 head=tail=new CNode<T>(0); 39 length=0; 40 } 41 42 template<class T> 43 void CList<T>::add(T data) 44 { 45 CNode<T> *pNode=new CNode<T>(data); 46 tail->next=pNode; 47 tail=pNode;//调整尾指针,指向新节点 48 length++; //节点总数加1 49 } 50 51 template<class T> 52 CNode<T> * CList<T>::getPointerByIndex(int idx) 53 { 54 CNode<T> *p; 55 int i=1; 56 if(idx<1 || idx>length) return NULL; 57 p=head; 58 59 while(i<=idx) 60 { 61 p=p->next; 62 i++; 63 } 64 return p; 65 } 66 67 template<class T> int CList<T>::insert(T data,int idx) 68 { 69 CNode<T> *p; 70 p=getPointerByIndex(idx); 71 if(p!=NULL) 72 { 73 CNode<T> *pNode=new CNode<T>(data); 74 pNode->next=p->next; 75 p->next=pNode; 76 length++; 77 return 1; //成功,返回1 78 } 79 return 0; 80 } 81 82 template<class T> int CList<T>::del(int idx) 83 { 84 CNode<T> *p,*q; 85 if(idx<1 || idx>length) 86 return 0; //失败,返回0 87 88 //获得要删除节点的前一个节点指针 89 if(idx==1) p=head; 90 else p=getPointerByIndex(idx); 91 92 //删除p节点的后一节点 93 q=p->next; //记住后一节点的指针 94 p->next=q->next; 95 //delete(q->data); 96 delete(q); 97 length--; 98 return 1;//成功,返回1 99 } 100 101 template<class T> T* CList<T>::toArray() 102 { 103 T *a=new T[length]; 104 CNode<T> *p; 105 p=head; 106 for(int i=0;i<length;i++) 107 { 108 p=p->next; //head节点没有数据,先移动再读取 109 a[i]=p->data; 110 } 111 return a; 112 } 113 114 115 template<class T> CList<T>::~CList() 116 { 117 CNode<T> *curr,*tmp; 118 curr=head; 119 for(int i=0;i<=length;i++) 120 { 121 tmp=curr; 122 curr=curr->next; 123 //delete(tmp->data); 124 delete(tmp); 125 } 126 } 127 128 void showList(CList<int> *li) 129 { 130 int *a=li->toArray(); 131 for(int i=0;i<li->getLength();i++) 132 cout<<a[i]<<" "; 133 cout<<"\n-------------------\n"; 134 } 135 136 void main() 137 { 138 CList<int> *li; 139 li=new CList<int>(); 140 //int a=100,b=101,c=102; 141 //li->add(&a); 142 //li->add(&b); 143 //li->add(&c); 144 li->add(100); 145 li->add(101); 146 li->add(102); 147 li->add(103); 148 showList(li); 149 li->insert(200,2); 150 showList(li); 151 li->insert(300,3); 152 showList(li); 153 li->del(1); 154 showList(li); 155 delete(li); 156 }
模板类不仅可以用于节点数据是对象指针的场合,也适用于节点数据是基本类型(如int)的场合。在此基础上,看到Java中的LinkedList<T>和C#中的List<T>,就不会有唐突的感觉了。稍微不同的是,Java和C#中去掉了“*”,把“->”变成“.”,对象指针也换了个名字叫“对象句柄”。