概念引入
在最开始的学习中,我们实现链表都需要依靠指针来连接链表的各个节点,但是,在一些语言中是不支持指针的,那么,在不使用指针的情况下,我们就无法实现链表了吗?当然不是,其实还有另一种链表的实现方式——游标实现!
思路分析
那么如果想不使用指针,我们必须了解指针在链表中的作用,我们来想一下,以前在写链表时,我们在那些地方用到了指针,首先当然是在链表的节点定义中,用指针来指向下一个节点,那么我们要想办法用一个东西代替它,我们发现,其实数组的下标完全可以充当指针,只要有了数组下标,就可以轻而易举的知道对应的元素了。以此为基础,就可以想到,构造一个结构体数组,里面有两个变量,一个存放元素的值,另一个存放下一个节点的下标值,充当指针作用。然后,我们要考虑分配和释放内存单元的问题,首先,我们可以选定一个节点作为头节点,让她一直指向下一个空的数组元素单元,由于数组的大小是有限的,所以我们还需要考虑让删除的元素重新利用。只要知道了这些,那么后面的具体实现其实就很简单了,与以前的写法相似。还要注意的的是,数组是需要我们自己先进性初始化的,必须让他们一开始就有一个指向顺序,如果不初始化就无法正确的分配新的空间,这一步在下面的main函数中给出。
具体实现
具体实现如下所示
//测试函数与初始化
int main()
{
int head=1; //链表头节点
cursor[0].next=2;//cursor[0]游标头节点,指向下一个空闲空间
cursor[head].next=0;//0代表NULL
int i;
for(i=2;i<9;i++){ //游标数组初始化
cursor[i].next=i+1;
}
Insert2(1,head,3);
Insert2(1,2,4);
Insert2(1,3,5);
Delect2(1,5);
Print2(head);
return 0;
}
//打印链表
void Print2(int head){
int p=cursor[head].next;
while(p!=0)
{
printf("%d",cursor[p].x);
p=cursor[p].next;
}
}
//节点定义
struct Node2{
int x; //存放元素
int next;//存放下一个节点下标
};
struct Node2 cursor[10]; //游标数组
//释放空间
void ffree(int s){
cursor[s].next=cursor[0].next; //让要释放的节点放到空闲节点和头节点之间,
cursor[0].next=s; //下次再申请空间是就是用这个被释放的节点
}
//分配空间
int mmalloc(){
int p=cursor[0].next; //头节点的下一个元素就是空余的空间
cursor[0].next=cursor[p].next;
return p;
}
//插入元素
void Insert2(int head,int p,int x){
int p1=mmalloc();
if(p1!=0){ //如果p1为0,则表示数组空间已满
cursor[p1].x=x;
cursor[p1].next=cursor[p].next;
cursor[p].next=p1;
}
}
//查找元素
int Find2(int head,int x){
int p=cursor[head].next; //循环查找,也可直接用下面一个函数
while(p!=0&&cursor[p].x!=x)//FindPrevious2()间接查找
p=cursor[p].next;
return p;
}
int Findprevious2(int head,int x){
int p=cursor[head].next;
if(cursor[p].x==x) //如果是第一个元素,则返回头节点
return head;
if(p!=0)
while(cursor[p].next!=0&&cursor[cursor[p].next].x!=x)//如果下标为p的元素下一个元素为空,或者
p=cursor[p].next; //下一个元素即为所需查找的元素,则结束
//循环
return p;
}
//原理与普通链表类似,只是写法稍微改一下
//删除元素
void Delect2(int l,int x){
int p=Find2(l,x);
if(p!=0){
int p2=Findprevious2(l,x);
cursor[p2].next=cursor[p].next;
ffree(p);
}
}