线性表-静态链表

逻辑结构上相邻的数据元素。存储在指定的一块内存空间中,数据元素只允许在该块内存空间中随机存放。该存储结构生成的链表称为静态链表。

静态链表与动态链表的区别:静态链表限制了数据元素存放的位置范围;动态链表存储元素范围是分配整个内存空间;

接下来看静态链表的数据结构:

typedef struct aa{
	int data;//数据域
	int cur;//游标 
}component;

核心:构建结构体数组,数组作为顺序存储元素、结构体里两个变量:data实现数据存储,cur实现指向下一个结点的在数组中位置,进而实现类似链表的功能

//创建备用链表
//@nxt:人为将结构体数组划分为备用部分,每次用从备用部分去空间,并把首元地址(存放最后一个数)拿出来当为链表是否满的标志位, 
void reserveArr(component *array){
	int i;
	for(i=0;i<maxSize;i++){
		array[i].cur = i+1;//将每个数组分量链接到一起 
	} 
	array[maxSize-1].cur =0;//链表最后一个结点的游标值为0即,最右一个结点游标对应存放a[0].data值 
} 

核心:数组首元素array[0]作为备用链表头结点,其游标cur值为0指向数组最后一个元素,同样作为数组是否满的标志位

arry[1]作为存放数据链表的头结点,array[1].data存放数据,array[1].cur存放下一个结点在数组中的位置,例如array[1].cur=3,则下一个结点为数组中array[3];这里与传统数组区别,数据元素连续的但在上=存储空间上不是连续的;

//提前分配空间(每次使用备用链表都需要分配空间?) 
int mallocArr(component *array){
	//若备用链表非空,则返回分配的结点下标,否则返回0(当分配最后一个结点时,该结点的游标值为0)
	int i = array[0].cur; //数组第一个元素里的 游标值,通过游标找到 一个结点在数组中的位置下标i 
	if(array[0].cur)
	{                               //重点:备用链表的游标存放下一结点在数组中的位置下标 
		array[0].cur = array[i].cur;//改变备用链表游标的值:通过游标i找到下一个结点在数组中的位置下标 
	}
	printf("\n i:%d ", i);//why?1,2,3,4,5?
	return i;
} 

在初始化静态链表时,需要分配链表空间,分为"备用区"和"数据区";在未给链表数据区赋值时,链表全部为备用区;

向静态链表存储数据时,从"备用区"拿去空间存储数据,转换为"数据区"

//初始化静态链表
int initArr(component *array){
	reserveArr(array);  //链接备用链表
	//从备用链表中拿出一个分量作为链表头结点,返回的事该分量的下标
	int boby = mallocArr(array);//@数组首元素对应发游标值 
	//声明一个变量,把它当为指针使,指向链表的最后一个结点,因为链表为空,所以和头结点重合
	int tempBody;
	tempBody = body; // 
	int i;
	for(i=1;i<5;i++){
		int j=mallocArr(array);//从备用链表中拿出空闲的分量
		array[tempBody].cur=j;//将申请的空线分量链接在链表的最后一个结点后面
		array[j].data='a'+i-1;//给新申请的分量的数据域初始化
		tempBody = j; 
	} 
	array[tempBody].cur=0;//新的链表最后一个结点的指针设置为0
	return body; 
} 

静态链表初始化时,先创建备用链表(将结构体数组分区,"备用区");提前分配空间,通过首元素对应的游标,找到一个"数据区"结点位置;然后对该结点进行赋值操作,并依次根据游标找到下一个结点位置在赋值....

void display(component *array,int body){
	int tempBody;
	tempBody = body;  //tempBody准备做遍历使用
	while(array[tempBody].cur){
		printf("%c %d ",array[tempBody].data,array[tempBody].cur);
		tempBody = array[tempBody].cur;
	} 
	printf("%c, %d\n",array[tempBody].data,array[tempBody].cur);

}

通过游标不为0(游标值为0位结构体数组最后一个元素)

//插入节点:向链表中插入数据,body表示链表的头结点在数组中的位置,add表示插入元素的位置,a表示要插入的数据
void insertArr(component *array,int body,int add, int a){
	//@找到插入位置的结点
	int tempBody =body;//tempBody做遍历结构体数组使用
	printf("body:%d\n",body);
	//找到要插入位置的上一个结点所在数组中的位置
	int i; 
	for(i=1;i<add;i++){
		tempBody = array[tempBody].cur;
	} 
	int insert = mallocArr(array);   //申请内存,准备插入
	array[insert].cur = array[tempBody].cur;   //首先要插入结点的游标等于要插入位置的上一个结点的游标
	printf("cur: %d\n", array[tempBody].cur);
	array[insert].data = a;
	array[tempBody].cur = insert;   //然后让上一结点的游标等于插入结点所在数组中的位置的下标 
	printf("insert: %d\n", insert);
	//将结点的游标域与上下结点的游标关联起来 
}

分析:

tempBody =1
i =1;i<add=3;i++
i=1; tempBody = array[1].cur ->2
i=2;tempBody = array[2].cur ->3
i=3;跳出循环

数组arry[0]为备用链表,array[1]为数据链表头元素

/*测试结果:
cur:1 cur:2 cur:3 cur:4 cur:5 cur:6 cur:7
 i:1
 i:2 j:2

 i:3 j:3

 i:4 j:4

 i:5 j:5

静态链表为:
 2 a 3 b 4 c 5 d, 0
查找数据域为‘a’的结点的位置:
3
将结点数据'b'改为'h'

无该元素
 2 a 3 b 4 c 5 d, 0
body:1

 i:6 
cur: 4
insert: 6
 2 a 3 b 6 e 4 c 5 d, 0
*/
//删除结点
void delArr(component *array,int body,char a){
	int tempBody = body;
	//找到被删除结点位置
	int i,j,del;
	while(array[tempBody].cur != a){
		tempBody = array[tempBody].cur;
		//当tempBody为0时,表示链表遍历结束,说明链表没有存储该数据的结点
		if(tempBody == 0){
			printf("链表中没有此数据\n");
			return; 
		} 
	} 
	/*
	while(array[tempBody].cur !=0){
		if(array[tempBody].data == a){
			return tempBody;
		}
		return -1;
	} */ 
	//找打被删除结点的上结点的
	del = tempBody;
	tempBody = body;
	//当循环到删除结点的上一结点时,跳出循环 
	while(array[tempBody].cur != del){
		tempBody = array[tempBody].cur;
	} 
	array[tempBody].cur=array[del].cur;
	freeArr(array,del);
}
//释放被删除结点空间
void freeArr(component *array, int k){
	array[k].cur = array[0].cur;
	array[0].cur = k;
}
 
//查找元素
//静态链表中数据查找,通过头结点(头结点在数组中的位置下标),遍历链表查找数据
//在以body作为头结点的链表中查找数据域为elem的结点在数组中的位置
int select(component *array,int body,char elem){
	int tempBody = body;
	//当游标值为0时,表示链表结束
	while(array[tempBody].cur !=0){
		if(array[tempBody].data == elem)
		{
			return tempBody;//返回数组的下标 
		}
		tempBody = array[tempBody].cur;//将当前下标数组元素的游标赋值给tempBody,继续循环 
	} 
	return -1;//返回-1,表示在链表中未找到该元素 
	
} 
//修改元素
void change(component *array, int body,char oldElem,char newElem){
	int add = select(array, body, oldElem);
	if(add == -1){  // add = -1 报错 
		printf("\n无该元素\n");
		return ;
	}
	array[add].data = newElem;
}
//测试结果
/*
cur:1 cur:2 cur:3 cur:4 cur:5 cur:6 cur:7
 i:1
 i:2 j:2

 i:3 j:3

 i:4 j:4

 i:5 j:5

静态链表为:
 2 a 3 b 4 c 5 d, 0
在第3位置上插入结点'e'
body:1

 i:6 cur: 4
insert: 6
 2 a 3 b 6 e 4 c 5 d, 0
删除数据域为'a'的结点
 3 b 6 e 4 c 5 d, 0
查找数据域为‘e’的结点的位置:
6
将结点数据'e'改为'h'
 3 b 6 h 4 c 5 d, 0

--------------------------------*/

完整代码

#include<stdio.h>
#define maxSize 7
/*
静态链表实现 
*/ 
typedef struct aa{
	int data;//数据域
	int cur;//游标 
}component;

void freeArr();
//创建备用链表
//@nxt:人为将结构体数组划分为备用部分,每次用从备用部分去空间,并把首元地址(存放最后一个数)拿出来当为链表是否满的标志位, 
void reserveArr(component *array){
	int i;
	for(i=0;i<maxSize;i++){
		array[i].cur = i+1;//将每个数组分量链接到一起 
		printf("cur:%d ",array[i].cur);
	} 
	array[maxSize-1].cur =0;//链表最后一个结点的游标值为0即,最右一个结点游标对应存放a[0].data值 
} 

//提前分配空间(每次使用备用链表都需要分配空间?) 
int mallocArr(component *array){
	//若备用链表非空,则返回分配的结点下标,否则返回0(当分配最后一个结点时,该结点的游标值为0)
	int i = array[0].cur; //数组第一个元素里的 游标值,通过游标找到 一个结点在数组中的位置下标i 
	if(array[0].cur)
	{                               //重点:备用链表的游标存放下一结点在数组中的位置下标 
		array[0].cur = array[i].cur;//改变备用链表游标的值:通过游标i找到下一个结点在数组中的位置下标 
	}
	printf("\n i:%d ", i);//why?1,2,3,4,5?
	return i;
} 
//初始化静态链表
int initArr(component *array){
	reserveArr(array);  //链接备用链表
	//从备用链表中拿出一个分量作为链表头结点,返回的事该分量的下标
	int body = mallocArr(array);//@数组首元素对应发游标值 
	//声明一个变量,把它当为指针使,指向链表的最后一个结点,因为链表为空,所以和头结点重合
	int tempBody;
	tempBody = body; // 
	int i;
	for(i=1;i<5;i++){
		int j=mallocArr(array);//从备用链表中拿出空闲的分量
		printf("j:%d\n", j);
		array[tempBody].cur=j;//将申请的空线分量链接在链表的最后一个结点后面
		array[j].data='a'+i-1;//给新申请的分量的数据域初始化
		tempBody = j; 
	} 
	array[tempBody].cur=0;//新的链表最后一个结点的指针设置为0
	return body; 
} 

void display(component *array,int body){
	int tempBody;
	tempBody = body;  //tempBody准备做遍历使用
	while(array[tempBody].cur){
		printf("%c %d ",array[tempBody].data,array[tempBody].cur);
		tempBody = array[tempBody].cur;
	} 
	printf("%c, %d\n",array[tempBody].data,array[tempBody].cur);

}
//静态链表中数据查找,通过头结点(头结点在数组中的位置下标),遍历链表查找数据
//在以body作为头结点的链表中查找数据域为elem的结点在数组中的位置
int select(component *array,int body,char elem){
	int tempBody = body;
	//当游标值为0时,表示链表结束
	while(array[tempBody].cur !=0){
		if(array[tempBody].data == elem)
		{
			return tempBody;//返回数组的下标 
		}
		tempBody = array[tempBody].cur;//将当前下标数组元素的游标赋值给tempBody,继续循环 
	} 
	return -1;//返回-1,表示在链表中未找到该元素 
	
} 

//静态链表中更改数据,通过查找算法找到要更改结点的位置,然后直接更改该结点的数据域
//一body作为头结点的链表中将数据域为oldElem的结点,数据域改为newELem
/*
void change(component *array, int body,char oldElem,char newElem){
	int tempBody = body;
	while(array[tempBody].cur !=0){
		if(array[tempBody].data == oldElem){
			array[tempBody].data = newElem;
		}
		tempBody = array[tempBody].cur;
	} 
}*/
void change(component *array, int body,char oldElem,char newElem){
	int add = select(array, body, oldElem);
	if(add == -1){  // add = -1 报错 
		printf("\n无该元素\n");
		return ;
	}
	array[add].data = newElem;
}
//插入节点:向链表中插入数据,body表示链表的头结点在数组中的位置,add表示插入元素的位置,a表示要插入的数据
void insertArr(component *array,int body,int add, int a){
	//@找到插入位置的结点
	int tempBody =body;//tempBody做遍历结构体数组使用
	printf("body:%d\n",body);
	//找到要插入位置的上一个结点所在数组中的位置
	int i; 
	for(i=1;i<add;i++){
		tempBody = array[tempBody].cur;
	} 
	int insert = mallocArr(array);   //申请内存,准备插入
	array[insert].cur = array[tempBody].cur;   //首先要插入结点的游标等于要插入位置的上一个结点的游标
	printf("cur: %d\n", array[tempBody].cur);
	array[insert].data = a;
	array[tempBody].cur = insert;   //然后让上一结点的游标等于插入结点所在数组中的位置的下标 
	printf("insert: %d\n", insert);
	//将结点的游标域与上下结点的游标关联起来 
} 

//
void delArr(component *array,int body,char a){
	int tempBody = body;
	//找到被删除结点位置
	int i,j,del;
	while(array[tempBody].data != a){
		tempBody = array[tempBody].cur;
		//当tempBody为0时,表示链表遍历结束,说明链表没有存储该数据的结点
		if(tempBody == 0){
			printf("链表中没有此数据\n");
			return; 
		} 
	} 
	/*
	while(array[tempBody].cur !=0){
		if(array[tempBody].data == a){
			return tempBody;
		}
		return -1;
	} */ 
	//找打被删除结点的上结点的
	del = tempBody;
	tempBody = body;
	//当循环到删除结点的上一结点时,跳出循环 
	while(array[tempBody].cur != del){
		tempBody = array[tempBody].cur;
	} 
	array[tempBody].cur=array[del].cur;
	freeArr(array,del);
}

void freeArr(component *array, int k){
	array[k].cur = array[0].cur;
	array[0].cur = k;
}
 
int main(){
	component array[maxSize]; //定义一个结构体数组 
	int body = initArr(array);//将结构体数组首地址传递非结构体指针 
	printf("\n静态链表为:\n");
	display(array,body); 
	printf("在第3位置上插入结点'e'\n");
	insertArr(array, body, 3,'e');
	display(array,body);
	printf("删除数据域为'a'的结点\n");
	delArr(array,body,'a');
	display(array,body);
	printf("查找数据域为‘e’的结点的位置:\n");
	int Add;
	Add = select(array, body,'e');//erro
	printf("%d\n",Add);
	printf("将结点数据'e'改为'h'\n"); 
	change(array,body,'e','h');
	display(array,body);

	return 0;
} 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值