C++静态链表的实现(包括各操作的成员函数)

[亡魂溺海] 提交于 2020-03-04 10:29:49

静态链表是用数组描述的链表,其实是为了给没有指针的语言设计的单链表的方法。尽管可能用不上,但这种思考方式是还是很巧妙的,利用游标来实现指针的作用,应该理解这种思想以备不时之需
,网上找的c++代码基本都有c的痕迹,就自己学了一天,其中加了大量的注释,希望对其他初学者有所帮助

  1 #include<iostream>
  2 #include<ctime>
  3 #include<cstdlib>
  4 using namespace std;
  5 #define MAXSIZE 1000
  6 
  7 #ifndef LIST_H
  8 #define LIST_H
  9 class node{//创建结点结构,包括数据和游标,游标记录下一个元素所对应的下标
 10 public:
 11     int cur;
 12     int data;
 13 };
 14 
 15 class List{
 16 public:
 17     List();//无参数的构造函数
 18     bool CreateList(int size);//初始链表
 19     int new_sl();//模仿普通链表的new分配内存空间
 20     void delete_sl(int i);//模仿普通链表的delete释放内存空间,这个形参i代表链表中将要释放的元素的下标
 21     void ClearList();//清空链表
 22     bool ListEmpty();//链表判空
 23     int ListLength();//获取链表长度
 24     bool GetElem(int i,int &e);//获取指定元素
 25     int LocateElem(int e);//寻找第一个等于e的数据元素的位序
 26     bool ChangeElem(int i,int e);//更改指定的元素
 27     void ListTraverse();//遍历链表
 28     bool ListInsert(int i,int Elem);//插入元素
 29     bool ListDelete(int i,int &Elem);//删除元素
 30 private:
 31     node space[MAXSIZE];//静态链表是由数组的下标实现指针的功能
 32     int length=0;
 33 };
 34 #endif // !LIST_H
 35 
 36 List::List(){
 37     length=0;
 38 }
 39 bool List::CreateList(int size){
 40     srand((unsigned int)time(NULL));//随机种子,为链表数据的创建提供随机值
 41     if(size<=0)//如果所要构建的链表长度小于等于0,返回false代表构建失败
 42         return false;
 43     for(int i=1;i<MAXSIZE-1;i++){//创建链表(包括备用链表和创建的链表),数组的下标0处储存备用链表(即尚未被使用的空间)的首个下标,故正式的元素从下标1开始
 44         space[i].cur=i+1;//每个元素都存储对应的游标,即下一个元素的下标,在初始化时就直接使用下一个元素的下标进行初始化
 45     }
 46     for(int i=1;i<=size;i++){
 47         space[i].data=rand()%100+1;//给创建的链表内的每个元素分配随机值
 48     }
 49     space[MAXSIZE-1].cur=1;//首个元素的游标由数组的最后一个元素存储
 50     length=size;
 51     return true;
 52 }
 53 int List::new_sl(){
 54     int i=space[0].cur;//获取备用链表的首个下标
 55     if(space[0].cur)
 56         space[0].cur=space[i].cur;//备用链表的原首下标被i拿去使用,现在需要创建新的首下标,原首下标对应的游标就是新的首下标
 57     return i;
 58 }
 59 void List::delete_sl(int i){
 60     space[i].cur=space[0].cur;/*将当前备用链表的首下标赋给将要释放的元素的游标,因为这个被释放的元素将成为备用链表的首个元素,那么当前备用链表的首下标就将成为这个元素的下一个元素的下标*/
 61     space[0].cur=i;//将被释放的元素下标的作为备用链表的首个下标
 62 }
 63 void List::ClearList(){
 64     int temp1=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
 65     for(int i=0;i<length;i++){//因为要清空整个链表,因此遍历
 66         int temp2=space[temp1].cur;//再创建一个变量来暂时存储将要释放的元素的游标,因为将要释放的元素一但释放,会丢失游标信息,导致遍历无法继续
 67         delete_sl(temp1);//释放元素
 68         temp1=temp2;//将游标信息赋回temp1,保证遍历继续进行
 69     }
 70 }
 71 bool List::ListEmpty(){
 72     return length==0;
 73 }
 74 int List::ListLength(){
 75     return length;
 76 }
 77 bool List::GetElem(int i,int &e){
 78     if(i<0||i>length)//如果元素位置小于1或超过链表长度,返回false代表获取失败
 79         return false;
 80     int temp=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
 81     for(int k=1;k<i;k++){//循环次数为元素位置减一,循环结束后temp变量是要获取的元素的上一个元素的游标,即我们要获取的元素的下标
 82         temp=space[temp].cur;//链表遍历的本质是游标的逐一传递,反复往后访问
 83     }
 84     e=space[temp].data;//将获取的元素的数据通过引用传递给e
 85     return true;
 86 }
 87 int List::LocateElem(int e){
 88     int i;
 89     int temp=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
 90     bool flag=false;//判断是否找到了想要的元素
 91     for(i=0;i<length;i++){//遍历链表,逐一寻找
 92         temp=space[temp].cur;//链表遍历的本质是游标的逐一传递,反复往后访问
 93         if(e==space[temp].data){//如果找到了想要的元素,跳出循环并将flag设为true代表找到了
 94             flag=true;
 95             break;
 96         }
 97     }
 98     if(!flag)
 99         return -1;//返回位置为-1代表没找到
100     else 
101     return i;//返回想要的元素在链表中的次序位置,即是链表中的第几个元素(还有一种是返回temp,是返回相应的下标)
102 }
103 bool List::ChangeElem(int i,int e){
104     if(i<0||i>length)//位置小于0或大于链表长度,返回false代表更改失败
105         return false;
106     int temp=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
107     for(int k=1;k<i;k++){//循环链表,游标达到指定位置为止
108         temp=space[temp].cur;//链表遍历的本质是游标的逐一传递,反复往后访问
109     }
110     space[temp].data=e;//改变目标元素的值
111     return true;
112 }
113 void List::ListTraverse(){
114     int temp=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
115     for(int i=0;i<length;i++){//标准遍历,没什么好说的
116         cout<<space[temp].data<<" ";
117         temp=space[temp].cur;
118     }
119     cout<<endl;
120 }
121 bool List::ListInsert(int i,int Elem){
122     if(i<0||i>length)//如果插入的位置小于0或大于链表长度,返回false代表插入失败
123         return false;
124     int temp=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
125     for(int k=1;k<i-1;k++){//循环次数为将插入的位置减2,此时temp为插入位置的前二个元素的游标(也就是插入位置的前一个元素的下标)
126         temp=space[temp].cur;
127     }
128     int pnew=new_sl();//创建新元素,分配内存(模拟)
129     space[pnew].cur=space[temp].cur;//将插入位置的游标赋给新元素的游标,此时新元素向后的接口完成
130     space[temp].cur=pnew;//将新元素的下标赋给插入位置的游标,此时新元素向前的接口完成
131     space[pnew].data=Elem;//将数据赋给插入的元素
132     length++;//长度增加
133     return true;
134 }
135 bool List::ListDelete(int i,int &Elem){
136     if(length==0||i<0||i>length)//如果删除的位置小于0或大于链表长度或链表为空,返回false代表删除失败
137         return false;
138     int temp=space[MAXSIZE-1].cur;//创建一个变量作为游标参与循环,首个元素的游标存在于数组的末尾,故将其赋给此变量
139     for(int k=1;k<i-1;k++){//循环次数为将删除的位置减2,此时temp为删除位置的前二个元素的游标(也就是删除位置前一个元素的下标)
140         temp=space[temp].cur;
141     }
142     int pde=space[temp].cur;//将删除位置的下标赋给一个整型变量
143     space[temp].cur=space[pde].cur;//将删除位置的游标赋给前一个元素的游标,此时完成了跨过删除位置的元素链接,可以释放删除元素了
144     Elem=space[pde].data;//将马上要被删除的元素赋给elem,避免数据彻底遗失
145     delete_sl(pde);//释放删除元素
146     length--;//长度减少
147     return true;
148 }
149 
150 int main(){//测试的主函数
151     List a;
152     a.CreateList(10);
153     cout<<"All elem:";
154     a.ListTraverse();
155     cout<<"Length:"<<a.ListLength()<<endl;
156     int e;
157     a.GetElem(5,e);
158     cout<<"Get elem:"<<e<<endl;
159     cout<<a.LocateElem(e)<<endl;
160     a.ChangeElem(5,6);
161     cout<<"Change elem:";
162     a.ListTraverse();
163     a.ListInsert(7,6);
164     cout<<"All elem:";
165     a.ListTraverse();
166     a.ListDelete(10,e);
167     cout<<"All elem:";
168     a.ListTraverse();
169     return 0;
170 }

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!