加油吧
1.静态链表的概念
首先百度了一下静态链表的概念(有点长)重点看一下标黄的部分
静态链表 ,也是线性存储结构的一种,它兼顾了顺序表和链表的优点于一身,可以看做是顺序表和链表的模版。 使用静态链表存储数据,数据全部存储在 数组 中(和顺序表一样),但存储位置是随机的,数据之间"一对一"的逻辑关系通过一个整形变量(称为"游标",和指针功能类似)(和链表类似)。通常,静态链表会将第一个数据元素放到数组下标为 1 的位置(a[1])中。 图 2 中,从 a[1] 存储的数据元素 1 开始,通过存储的游标变量 3,就可以在 a[3] 中找到元素 1 的直接后继元素 2;同样,通过元素 a[3] 存储的游标变量 5,可以在 a[5] 中找到元素 2 的直接后继元素 3,这样的循环过程直到某元素的游标变量为 0 截止(因为 a[0] 默认不存储数据元素)。
2.代码如下
(1)slist.h (头文件)
//定义结构体
#define MAXSIZE 10 //不可扩容的链表 注意语句的后面没有分号;
typedef struct SNode
{
int data;//数据域
int next;//存数据的地址也就是下标
}SNoed, SLinkList[MAXSIZE];
//初始化
void InitList(SNode* ps);
//头插
bool Insert_head(SNode* ps, int val);
//尾插
bool Insert_tail(SNode* ps, int val);
//判空
bool IsEmpty(SNode* ps);
//获取数据节点的个数
int GetLength(SNode* ps);
//获取前驱
int GetPrio(SNode* ps, int key);
//查找,在ps中查找第一个key值,找到返回节点的下标,没有找到返回-1
int Search(SNode* ps, int key);
//删除第一个val的值
bool DelVal(SNode* ps, int val);
//输出
void Show(SNode* ps);
//清空数据
void Clear(SNode* ps);
//销毁整个内存
void Destroy(SNode* ps);
(2)slist.cpp(函数实现的文件)
#include"slist.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//初始化
void InitList(SNode* ps)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return;
}
ps[0].next = 0;//类似于单链表中将下一节点制空
for (int i = 1; i < MAXSIZE; i++)//遍历查找
{
ps[i].next = i + 1;//下标连续
}
ps[MAXSIZE - 1].next = 1;//空闲链表的表头为1
}
static bool IsFull(SNode* ps)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return false;
}
return ps[1].next == 1;//在初始化中说1是空闲链表的表头 所以如果平时ps[1]的next指向了表头 代表已经没有空闲节点了
}
//头插
bool Insert_head(SNode* ps, int val)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return false;
}
if (IsFull(ps))//总是会忘了IsFull后面括号里的东西
{
return false;
}
//1.获取一个空闲节点
int p = ps[1].next;
//2.将空闲节点从空闲链表中删除
ps[1].next = ps[p].next;
//3.放入数据
ps[p].data = val;
//4.连接
ps[p].next = ps[0].next;//还是先绑后面 ps[0]相当于单链表中的plist
ps[0].next = p;
return true;///这步容易忘了
}
//尾插
bool Insert_tail(SNode* ps, int val)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return false;
}
if (IsFull(ps))
{
return false;
}
//1.获取一个空节点
int p = ps[1].next;
//2.将该节点从空闲链表中删除
ps[1].next = ps[p].next;
//3.找到链表的尾巴(尾插一般都有这一步,区别于头插)
int q = 0;
for (q; ps[q].next != 0; q = ps[q].next)
{
;
}
//4.填数据
ps[p].data = val;
//5.连接
ps[p].next = ps[q].next;
ps[q].next = p;
return true;
}
//判空
bool IsEmpty(SNode* ps)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return false;
}
return ps[0].next == 0;//空闲链表的下标为0了代表没有空闲节点
}
//获取数据节点的个数
int GetLength(SNode* ps)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return -1;
}
int count = 0;
for (int p = ps[0].next; p != 0; p = ps[p].next)
{
count++;
}
return count;
}
//查找,在ps中查找第一个key值,找到返回节点的下标,没有找到返回-1
int Search(SNode* ps, int key)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return -1;
}
for (int p = ps[0].next; p != 0; p = ps[p].next)
{
if (ps[p].data == key)
{
return p;
}
}
return -1;
}
//获取前驱
int GetPrio(SNode* ps, int key)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return -1;
}
int p = 0;
for (p; ps[p].next != 0; p = ps[p].next)
{
int q = ps[p].next;
if (ps[q].data == key)
{
return p;
}
}
return -1;
}
//删除第一个val的值
bool DelVal(SNode* ps, int val)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return false;
}
//获取val的前驱
int p = GetPrio(ps, val);
if (p < 0)
{
return false;
}
//将节点从有效数据链中删除
int q = ps[p].next;
ps[p].next = ps[q].next;
//将节点放到无效数据链中***不同于之前的容易忘记
ps[q].next = ps[1].next;
ps[1].next = q;
return true;
}
//输出
void Show(SNode* ps)
{
assert(ps != NULL);//判空
if (ps == NULL)
{
return ;
}
for (int p = ps[0].next; p != 0; p = ps[p].next)
{
printf("%5d", ps[p].data);
}
printf("\n");
}
//清空数据
void Clear(SNode* ps)
{
InitList(ps);//没有数据的时候就和初始化的结果是一样的
}
//销毁整个内存
void Destroy(SNode* ps)
{
Clear(ps);
}
(3)test.cpp(测试文件)
#include"slist.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int main()
{
SLinkList s;//定义一个静态链表s
InitList(s);//初始化
//for (int i = 0; i < 10; i++)
//{
// Insert_tail(s, i);//尾插
//}
//Show(s);
for (int i = 0; i < 10; i++)
{
Insert_head(s, i);//头插
}
//Show(s);
/*int res = GetLength(s);
printf("%d\n", res);*/
/*DelVal(s, 2);
Show(s);*/
/*int sum = Search(s, 3);
printf("3位置是%d\n", sum);*/
Clear(s);
Show(s);
return 0;
}
(4)用Visual Studio 2019运行 截图如下