摘要:事实上,静态链表可以让我们更好地理解空间分配机制。由我们对一片空间来进行分配管理,如我们在链表中就用到了int *used来检查这篇空间是否被占用,模拟操作系统是如何判断一片空间是否被占用。
再者,我们对于静态链表的地址模拟选用了整型int next,用next来代表下一个访问数据的下标,实际上下标其实对于数组来说就是他的地址,我们有了地址就可以访问到对应地址存放的数据。这个东西对应的就是单链表的next,只不过单链表的next是操作系统分配给我们的真实地址,我们的目的就是模拟。
其实对于后续的插入,删除等基本操作,就和我们单链表差不太多。只是多了一步我们需要自己来确定是否有空间来进行操作,并且分配空间。
话不多说,我们来看一看静态链表到底是如何运转的。
一.代码块
1)创建链表
#define DEFAULT_SIZE 5 //与单链表不同,该链表我们所能控制的空间大小是一开始就确定的。
typedef struct StaticLinkedNode
{
char data; //数据域
int next; //这个是用来存放数组下标,即下一个数据地址的(我们用-1来模拟NULL)
} *NodePtr;
typedef struct StaticLinkedList
{
NodePtr nodes;
int* used; //我们用used来确定空间是否被占用,占用赋1,未占用赋0;
} *ListPtr;
2)初始化链表
ListPtr initLinkedList()
{
ListPtr tempPtr = (ListPtr)malloc(sizeof(struct StaticLinkedList));
//所有的空间都提前申请好了
tempPtr->nodes = (NodePtr)malloc(sizeof(struct StaticLinkedNode) * DEFAULT_SIZE);
tempPtr->used = (int*)malloc(sizeof(int) * DEFAULT_SIZE);
// 第一个结点数据域不能存放东西,但是他要占用我们申请的一个空间,所以我们实际能用的空间要比申请的少一个
tempPtr->nodes[0].data = '\0';
tempPtr->nodes[0].next = -1;
//这里初始化只有第一个结点是被占用的,我们给used赋值。
tempPtr->used[0] = 1;
int i;
for (i = 1; i < DEFAULT_SIZE; i ++)
{
tempPtr->used[i] = 0;
}
return tempPtr;
}
3)打印链表
void printList(ListPtr paraListPtr)
{
//这里如果从第0个开始打印,就把头结点的'\0'也打印出来了
int p = paraListPtr->nodes[0].next;
//这样写直接从头结点后面第一个数据开始打印
while (p != -1)
{
printf("%c", paraListPtr->nodes[p].data);
p = paraListPtr->nodes[p].next;
}
printf("\r\n");
}
4)指定位置插入元素
void insertElement(ListPtr paraListPtr, char paraChar, int paraPosition){
int p, q, i;
//第一步仍然是帮助p找到他的位置
p = 0;
//就相当于单链表里面的 p = paraHeader;
for (i = 0; i < paraPosition;<