游标实习表(C语言)
-
理解:(假如数组的子集是称为单元,表的子集称为元素)游标实现表的实质是,用数组存储表的元素,表的元素包括值域和next域(仿指针域),next域是用来指向表的下一个单元在数组中存储的的位置。
-
怎么确定一个表的开头和结尾:首先我们要知道删除操作是进行的覆盖,而表头是表的起始点,所以无法覆盖,也就无法进行删除操作,所以一般来说,表头的一般在数组中的位置是固定的,往往是数组的第一个位置,除非你将表头的next域抹去,使其指向为空的数组单元或指向本身(此时表头变为原本表的第二个元素),否则表头在数组中的位置和作为表的起始单元是固定的。表尾就很简单,只要他的next域指向一个特定的值,我们设为-1,这样我们只要找到表的元素的next值为-1的就找到了表尾元素,或者再表中进行等于表长次数的循环,也可以找到表尾。
-
表要具备的要素:表头,表尾,元素,表长。
-
表的图示:
-
表元素next的初始化问题:书中是在以1为开始自加来对next赋值。如下图
-
表的添加操作:有表头添加,表中添加,表尾添加。怎么判断添加属于表头添加,当表为空时或分配的表的地址为0时即为表头添加(假设数组下标为0的空间充当表头)。表中添加则是当添加的位置小于表的长度。表尾添加则是当插入的位置大于表的长度。
-
如何给元素的添加分配空间:若表元素之间有数组单元为空(之气进行过删除操作),则优先适用这些单元。若没有,则使用表外的数组空间单元。
-
表元素的删除问题:循环找到要删除的元素的前一个的数组下标,将该下标的next指向要删除的那个元素的next即可(覆盖操作——前一个指向后一个),同时将被删除的元素的数组下标保存至另一个空间(有点类似于书中的双空间,只不过书中的是删除的元素在形成一个表),当需要添加时,分配的空间下标会优先从这里获取,避免造成空间浪费。
-
表的输出问题:表的输出一定是按照表的元素的next来进行循环,来充当数组下标进行输出表的元素的。而不是单纯的按数组下标输出。
-
表的查找问题:一般建议为按值查找。利用next进行循坏,再定义一个变量i从一开始在循环体内进行自加,最后输出的i即为该元素在表中的位置。
-
代码如下:
#include<stdio.h>
#include<stdlib.h>//初始化全为-1版本
typedef int ListItem;
typedef struct node *Node;
typedef struct node{//表
ListItem element;
int next;
}Sun;
typedef struct list *List;
typedef struct list{
int first1,first2,size,length,cnt,dog,position;//length用来记录表长 ,cnt用来充当数组下标
int *tempory;//用来记录被删除的元素的数组下标,下次添加时优先使用这些下标
Node S;
}Sun1;
List ListInit(List L,int max)
{
L->size = max;// 数组大小
L->S = (Node)malloc(sizeof(*L->S)*max); //分配数组空间
L->first1 = 0; //即将分配的数组下标
L->first2 = 0;//记录表头的坐标
L->cnt = 0; //数组下标
L->length = 0;//表长
L->dog = 0; //记录上一次分配的数组下标(非因删除导致的重新分配)
L->tempory = (int *)malloc((sizeof (int))*10);
for(int j=0;j<10;j++) L->tempory[j] = 0; //记录数组初始化全为0
for(int i=0;i<max;i++)L->S[i].next = -1;//全初始化为-1
return L;
}
int Spacemalloc(List L)//模仿malloc函数
{
int p,q;
q = L->cnt;
if(L->tempory[0] != 0){
L->first1 = L->tempory[q-1];//该记录数组是从0添加,所以要减一个1
L->tempory[q-1] = 0;//用完后赋值为0,方标调用后面的释放的数组下标
L->cnt--;
}
else{
if(L->dog != 0)L->first1 = L->dog; //当被记录的用完之后,first重新返回表外的数组单元
}
p = L->first1;
L->first1++;//当tempory不为空时不需要加,但加了也没事。
return p;//返回分配的地址
}
void Spacefree(List L,int k)//这里的k是元素在数组中的位置。
{
int i = L->cnt;
L->dog = L->first1;//记录删除之前的L->first1,方便将删除的空间利用完后再到数组的剩余空间分配
L->tempory[i] = k;//将被释放的空间下标存储至数组中。
L->S[k].next = -1; //删除之后指向-1(一定),方便表尾添加的时候当作结束值.
L->cnt++;//数组实际长度+1
L->length--;//表长度-1
}
int ListFind(List L,ListItem x) //查找元素x在表中的位置
{
int p = L->first2;
int i = 1;
while(p != -1 && L->S[p].element != x){
p = L->S[p].next;
i++;
}
return i;
}
void ListInsert(List L,int k,ListItem x)
{
if(L->length -1 == L->size){//表从1开始计数,数组从0开始。所以减个1
printf("表已满\n");
exit(0);
}
int p,y,d,q,g,z;
g = L->cnt;
p = 0;
d=1;
g=0;
z=0;
y = Spacemalloc(L);
printf("分配的地址为:%d\n",y);
if(L->length <= k){//判断是否表中插入
printf("进入到表尾插入");
if(y == 0)L->S[y].next = L->first1;//判断是否表头插入
else{
while( L->S[p].next != -1 && d<L->length)//寻找表尾
{
p=L->S[p].next;
d++;
}
L->S[p].next = y;
if(g>1){//若tempory数组中不为空
if(g>2) L->S[y].next = L->tempory[g-2];
else L->S[y].next = L->dog;//当数组中只有一个元素时
}
}
}
else{printf("进入到表中插入");
for(int i=1;i<k;i++)p=L->S[p].next;//
q = L->S[p].next;
L->S[y].next = q;//前一个指向插入那个的下标
L->S[p].next = y; //插入那个指向后一个的下标,即是前一个的next
L->length++;//插入完成之后表立即加1
}
L->S[y].element = x;//赋值
L->length++;
}
void ListDellete(List L, ListItem x)
{
int p,q,j;
j = ListFind(L,x) ;
printf("查看寻找是否出错j==== %d ",j);
p = L->first2;
if(j<0 || j > L->size){
printf("输入错误\n");
exit(0);
}
else{
for(int t=1;t<j-1;t++) p = L->S[p].next; // 不能用next来作为循环的参数,因为其指向的地址是多变的,有时并不按顺序排列。
q = L->S[p].next;
L->S[p].next = L->S[q].next;//覆盖
Spacefree(L,q);//释放删除的元素的下标
}
}
void ListTravel(List L)
{
int p=L->first2;
while(p != -1 && L->S[p].element){
printf("(%d %d %d ) ",L->S[p].element,L->S[p].next,p);
p = L->S[p].next;
}
printf("\n___________________________\n");
}
int main()
{
int a;
List L = (List)malloc(sizeof *L);
L=ListInit(L,7);
ListInsert(L,0,8);
ListTravel(L);
ListInsert(L,1,6);
ListTravel(L);
printf("%d\n",L->first1);
printf("%d",L->length);
ListInsert(L,2,4);
ListTravel(L);
ListInsert(L,3,9);
ListTravel(L);
ListInsert(L,4,10);
ListTravel(L);
ListInsert(L,2,22);
ListTravel(L);
ListDellete(L,9);
printf("要删除的元素是9\n");
printf("删除后的表为:");
ListTravel(L);
printf("要删除的元素是6\n");
ListDellete(L,6);
printf("删除后的表为:");
ListTravel(L);
printf("5号位置插入99\n");
ListInsert(L,5,99);
ListTravel(L);
printf("6号位置插入100\n");
ListInsert(L,6,100);
ListTravel(L);
printf("7号位置插入100\n");
ListInsert(L,7,101);
ListTravel(L);
printf("多次的删除和插入操作均正确\n");
printf("\n");
}
- 运行结果如下