线性表
线性表的定义:
定义n个数据元素的有限序列,记作(a1, a2, …, an)ai 是表中数据元素,n 是表长度
线性表的特点:
除第一个元素外,其他每一个元素有一个且仅有一个
直接前驱。
除最后一个元素外其他每一个元素有一个且仅有一个
直接后继。
顺序表的定义和特点
定义 将线性表中的元素相继存放在一个连续的存储空间中。
可利用一维数组描述存储结构
特点 线性表的顺序存储方式
遍历 顺序访问, 可以随机存取
头文件
#ifndef SEQUENCELIST_H
#define SEQUENCELIST_H //必须和上面的一模一样,而且是大写
#include<stdio.h>
#include<stdlib.h>
#include<time.h> //用到的头文件
#define SIZE 10
#define SUCCESS 10000
#define FAILURE 10001 //宏定义的常量
struct Sequence // 顺序表的信息
{
int *data;
int lengrh;
};
typedef struct Sequence seq; //更名,方便书写
int SequenceInit (seq *l);
int SequnenceInsert (seq *l,int p, int e);
int SequnenceTraverse(seq l);
int SequnenceLength(seq l);
int SequnenceFind(seq l, int p, int *e);
int SequnenceLocate(seq l, int e, int (*p)(int , int));
int Getprior(seq l, int e);
int GetNext(seq l, int e);
int SequenceDel(seq *l, int p);
int SequenceClear(seq *l);
int SequenceDestroy(seq *l);
//一个程序的编译时先要预处理,也就是说要先把头文件该展开的展开,该打开的打开。
而程序是由主函数main开始走动的,遇到需要调用的子函数,发现头文件里没有,
这时我们就需要在头文件中声明下子函数,方便与找到它的文件。
(如果调用的字函数没和主函数写在同一个文件),还有声明调用的子函数后面需要加分号。
#endif
还有头文件的文件名必须是头文件的名字,可以不用大写。
eg上诉头文件,可以命名为 Sequence.h
记住,后面不是跟.c ,而是上面的SEQUENCE_H的尾巴 _H 变成 .h
调用的子函数存在的文件
#include "SequenceList.h" //头文件因为是刚刚在这个目录下创建的。所以用“”括起来,“”的意思是现在当前目录下寻找这个头文件,
找不到的话就去库里或者根目录下找。<>的意思是直接去根目录或者库里找。
/*函数描述:顺序表的初始化
函数参数 : 顺序表
函数返回值: 成功返回success 失败返回failure
*/
int SequenceInit(Seq *l)
{
if(NULL == l) // 入参判断,防止传入空指针。也是判断是传入的是否 是有效指针。
{
return FAILURE;
}
l -> data = (int *)malloc(sizeof(int)*SIZE);
if (NULL == l -> data)
{
return FAILURE;
}
l -> length = 0; // 长度初始化成 0
return SUCCESS;
}
/* 函数描述 : 往顺序表指定位置插入元素
函数参数: 顺序表 插入的位置 插入的元素
函数返回值 : 成功返回success 失败返回failure
*/
int SequenceInsert(seq *l, int p, int e)
{
if(NULL == 1)
{
return FAILURE;
}
if(p > 1 -> length + 1) //判断位置是否合法
{
return FAILURE;
}
if (l -> length >= SIZE) //判断顺序表是否满
{
return FAILURE;
}
if (NULL == l -> data) //判断传过来的元素是否是空指针
{
return FAILURE;
}
int i;
for(i = 0; i < l -> length - p + 1; i++) // l -> length相当于主函数里传入的元素的个数
{
l -> data[l -> length - i] = l -> data[l -> length - i -1];
//顺序表也和栈空间差不多,先进后出。这式子的意思是把数据里的第7位送进顺序表,放在第一位;
在进去第二位元素时,地位7位数据移到第2位。。。。这样数据第7位就在顺序表第7位上了。
}
l -> data[p -1] = e;
l -> length++;
return SUCCESS;
}
/*函数描述:打印顺序表中的元素
函数参数: 顺序表
函数返回值: 无
*/
void SequenceTraverse(seq l)
{
int i;
for(i = 0; i < l.length; i++)
{
printf("%d ",l.data[i]);
}
}
int SequenceLength(seq l)
{
return l.length;
}
/*函数描述 : 根据位置查找元素
函数参数: 顺序表 位置 保存找到的元素
函数返回值 : 元素存在,返回success 元素不存在 返回 failure
*/
int SequenceFind(seq l,int p,int *e)
{
if(p > l.length || p <= 0) //判断位置是否合法
{
return FAILURE;
}
if (NULL == e) //判断传的随机数是否空指针
{
return FAILURE;
}
*e = l.data[p - 1]; //保存找到的元素
return SUCCESS;
}
/*
函数描述:根据元素找位置
函数参数:顺序表 要查找的元素 函数指针(用于判断两个数的关系)
函数返回值: 如果元素存在,返回对应的位置,如果不存在,返回失败
*/
int SequenceLocate(seq l, int e, int (*p)(int, int))
{
int i;
for(i = 0; i < l.length; i++)
{
if (p(e, l.data[i])) // if(e== l.data[i])
{
return i + 1;
}
}
return FAILURE;
}
/*
函数描述: 查找元素前驱
函数参数: 顺序表 要查找的元素
函数返回值: 如果元素前驱不存在,返回FAILURE;如果存在,返回这个元素的前驱。
*/
int GetPrior(seq l, int e)
{
int i;
for(i = 1; i < l.length; i++) //排除第一个,第一个没有前驱
{
if(e == l.data[i])
{
return l.data[i - 1];
}
}
return l.data[i - 1];
}
/*
函数描述: 查找后继节点。
函数参数: 顺序表,要查找的元素
函数返回值:如果元素存在后继节点,返回这个元素的前驱值,如果元素不存在后继节点,返回FAILUR
*/
int GetNext (seq l, int e)
{
int i;
for (i = 0; i < l.length - 1; i++)
{
if(e == l.data[i])
{
return l.data[i + 1];
}
}
return FAILURE;
}
/*
函数描述 : 删除指定位置的元素
函数参数: 顺序表指针 删除元素的位置
函数返回值 : 成功返回删除的元素值 失败返回FAILURE
*/
int SequenceDel(seq *l, int p)
{
if(NULL ==1)
{
return FAILURE;
}
if(p <= 0 || p > l -> length)
{
return FAILURE;
}
int num = l -> data[p - 1];
int i;
for(i = 0; i < l -> length - p; i++)
{
l ->data[p - 1 + i] = l -> data[p+i];
}
l -> length--;
return num;
}
/*
函数描述:清空顺序表
函数参数: 顺序表的地址
函数返回值: 清空成功返回SUCSESS ,清空失败,返回FAILURE
int SequenceClear(seq *l)
{
if( NULL == l)
{
return FAILURE;
}
l ->length = 0;
return SUCCESS;
}
/*
函数描述:删除顺序表
函数参数: 顺序表的地址
函数返回值:失败返回FAILURE,成功返回SUCCESS
int SequenceDestroy(seq *l)
{
if(NULL == l)
{
return FAILURE;
}
l -> length = 0;
free(l -> data);
l -> data = NULL;
return SUCCESS;
}
主函数文件(main函数)
#include "SequenceList.h" //因为文件运行,第一步先预处理,进行头文件的展开或者打开所需内容
int equal (int x, int y) //使用回调函数的方式(函数指针) 比较大小方便从小到大或者从大到小输出
{
return(x==y) ? 1: 0 ;
}
int main()
{
srand(time (NULL)); //srand(time)关键字,随时间随机产生的数。
seq list; //创建顺序表
int ret;
ret = SequenceInit (&list) //顺序表初始化 //地址传递,如果要修改实参的值需要传地址
if(SUCCESS == ret)
{
printf("初始化成功\n");
}
else
{
printf("初始化失败\n");
}
int i, num;
for (i = 0; i < 7; i++) // i < 7 相当于把插入的7个数当成长度。
{
num = rand() %10; //随机插入10的余数
ret = SequenceInsert(&list, i + 1, num);
if(SUCCESS == ret)
{
printf("插入%d成功!\n",num);
}
else
{
printf("插入%d失败!\n",num);
}
}
SwquenceTraverse(list);
printf("\n");
printf("%d\n",SequenceLength(list));
//根据位置查找元素
int p =3;
ret = SequenceFind(list, p, &num);
if(SUCCESS == ret)
{
printf("%d-th 元素是 %d\n",p, num);
}
else
{
printf("元素%d不存在\n", num);
}
//根据元素查找位置
num = 6;
ret = SequenceLocate(list, num, equal);
if(FAILURE ==ret)
{
printf("元素%d不存在\n", num);
}
else
{
printf("%d是第%d个元素\n", num, ret);
}
num = 6
ret = GetPrior(list, num);
if(FAILURE ==ret)
{
printf("%d没有前驱\n",num, ret);
}
else
{
printf("%d前驱是%d\n", num, ret);
}
ret = GetNext(list, num);
if(FAILURE == ret)
{
printf("%d没有后继\n", num);
}
else
{
printf("%d后继是%d\n", num, ret);
}
// 删除指定位置的元素
for(i = 0; i < 3; i++)
{
p = rand() %15;
ret = SequenceDel(&list,p);
if(FAILURE == ret)
{
printf("%d-th个元素不存在\n", p);
}
else
{
printf("%d-th个元素删除成功,元素是%d\n", p, ret, );
}
}
//清空顺序表的元素
ret = SequenceClear(&list);
if(SUCCESS == ret)
{
printf("清空成功\n");
}
else
{
printf("清空失败\n");
}
SequenceTraverse(list);
printf("\n");
//删除顺序表
ret = SequenceDestory(&list);
if(SUCCESS == ret)
{
printf("销毁成功\n");
}
else
{
printf("销毁失败\n");
}
for(i = 0; i < 7; i++)
{
num = rand() % 10;
ret = SequenceInsret(&list, i + 1, num);
if(SUCCESS == ret)
{
printf("插入%d成功!\n",num);
}
else
{
printf("插入%d失败!\n", num);
}
}
return 0;
}