游标实现表(C语言)

游标实习表(C语言)

  1. 理解:(假如数组的子集是称为单元,表的子集称为元素)游标实现表的实质是,用数组存储表的元素,表的元素包括值域和next域(仿指针域),next域是用来指向表的下一个单元在数组中存储的的位置。

  2. 怎么确定一个表的开头和结尾:首先我们要知道删除操作是进行的覆盖,而表头是表的起始点,所以无法覆盖,也就无法进行删除操作,所以一般来说,表头的一般在数组中的位置是固定的,往往是数组的第一个位置,除非你将表头的next域抹去,使其指向为空的数组单元或指向本身(此时表头变为原本表的第二个元素),否则表头在数组中的位置和作为表的起始单元是固定的。表尾就很简单,只要他的next域指向一个特定的值,我们设为-1,这样我们只要找到表的元素的next值为-1的就找到了表尾元素,或者再表中进行等于表长次数的循环,也可以找到表尾。

  3. 表要具备的要素:表头,表尾,元素,表长。

  4. 表的图示:在这里插入图片描述
    在这里插入图片描述

  5. 表元素next的初始化问题:书中是在以1为开始自加来对next赋值。如下图书中的表

  6. 表的添加操作:有表头添加,表中添加,表尾添加。怎么判断添加属于表头添加,当表为空时或分配的表的地址为0时即为表头添加(假设数组下标为0的空间充当表头)。表中添加则是当添加的位置小于表的长度。表尾添加则是当插入的位置大于表的长度。

  7. 如何给元素的添加分配空间:若表元素之间有数组单元为空(之气进行过删除操作),则优先适用这些单元。若没有,则使用表外的数组空间单元。

  8. 表元素的删除问题:循环找到要删除的元素的前一个的数组下标,将该下标的next指向要删除的那个元素的next即可(覆盖操作——前一个指向后一个),同时将被删除的元素的数组下标保存至另一个空间(有点类似于书中的双空间,只不过书中的是删除的元素在形成一个表),当需要添加时,分配的空间下标会优先从这里获取,避免造成空间浪费。

  9. 表的输出问题:表的输出一定是按照表的元素的next来进行循环,来充当数组下标进行输出表的元素的。而不是单纯的按数组下标输出。

  10. 表的查找问题:一般建议为按值查找。利用next进行循坏,再定义一个变量i从一开始在循环体内进行自加,最后输出的i即为该元素在表中的位置。

  11. 代码如下:

#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");
}
  1. 运行结果如下
    在这里插入图片描述
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值