数据结构基本概念
- 数据:数据就是信息的载体,是能够输入到计算机中并能被计算机识别,存储和处理的符号集合。
- 数据元素:数据元素是数据的基本单位,在程序中作为一个整体进行考虑和处理,有若干基本项组成。
- 数据项:数据项就是构成数据元素的最小单位,也就是一个数据元素可以由多个数据项组成
数据的逻辑结构
数据结构分为逻辑结构和物理结构。
逻辑结构
逻辑结构是指数据对象中数据元素之间的相互关系
四种逻辑结构如下,
- 集合结构:数据元素除了同属于一个集合外,它们之间没有其他关系
- 线性结构:数据元素之间是一对一关系
- 树形结构:数据元素之间呈现一对多关系
- 图形结构:数据元素是多对多关系
物理结构
物理结构是指数据的逻辑结构在计算机中的存储形式,也就是在计算机中的具体实现方法,因此也称为存储结构。
数据元素存储结构形式分为顺序存储和链式存储。
- 顺序存储:把数据元素按照逻辑顺序存放在一片地址连续的存储单元里
- 链式存储:把数据元素存放在任意的存储单元里,这组存储单元可以是连续的也可以是不连续的,这些元素用地址(或者链指针)建立他们的联系
除了上述两种存储还有索引存储,散列存储,
- 索引存储:就是在存储数据时建立一个附加的索引表,也就是建立一个目录(类似)
- 散列存储:根据数据元素的特殊字段,也就是关键字计算元素的存放地址,然后数据元素按地址存放。
线性表
线性表简介
其中D表示数据(Data),R表示关系(Relation),可以表示成如下,
其中叫做有序对,表示任意相邻元素之间的先后次序
是
的直接前驱,
是
的直接后继
总结线性表特征:
- 对于非空线性表,表头没有前驱元素
- 对于非空线性表,表尾没有后继元素
- 除此以外其他每个元素都有且仅有一个直接前驱和直接后继
线性表顺序存储
如果将线性表中的各个元素依次存储在计算机一片连续的存储空间,就是线性表的顺序存储,后续直接叫做顺序表。
顺序存储的优点:
- 逻辑上相邻的两个元素存储位置是相邻的,对数据元素的存取或者查找方便
- 存储密度高,存储的区域没有空位
顺序存储的缺点:
- 对表的插入和删除等运算时间复杂度差
顺序表C语言编写
线性表顺序存储在C语言下编写的结构代码如下,
#define MAXSIZE 100
typedef int data_t; /*data_t类型根据实际情况而定,这里为int/
typedef struct
{
data_t data[MAXSIZE]; /*数组,存储数据元素*/
int last; /*线性表当前长度,也就是线性表中实际元素的数量*/
} sqlist,*sqlink;
存储结构如下,
下面我们将编写一些顺序表相关的函数,在编写时我们一般会创建三个文件,分别是sqlist.h,sqlist.c,test.c,其中sqlist.h用于编写一些数据结构的定义和函数结构,sqlist.c用于编写函数具体实现,test.c用于测试每个函数是否正确。
这样编写可以让我们写的程序结构清晰,且容易进行软件复用。
在sqlist.h文件中,编写的程序如下,
typedef int data_t;
#define MAXSIZE 128
/*struct sqlist_t
{
data_t data[MAXSIZE];
int last;
};
typedef struct sqlist_t sqlist;
typedef struct sqlist_t *sqlist;
*/
/*为了方便理解,上面创建结构体并进行typedef和下面是一样的*/
/*定义线性表*/
typedef struct
{
data_t data[MAXSIZE];/* data */
int last;/* data */
}sqlist,*sqlink;
/*对线性表的一些操作API函数,具体作用请看C文件的部分*/
sqlink list_create();
int list_clear(sqlink L);
int list_free(sqlink L);
int list_empty(sqlink L);
int list_length(sqlink L);
int list_locate(sqlink L,data_t value);
int list_insert(sqlink L,data_t value,int pos);
int list_delete(sqlink L,int pos);
int list_merge(sqlink L1,sqlink L2);
int list_purge(sqlink L);
int list_show(sqlink L);
在sqlist.h文件中,我们编写相关函数的具体实现,以下是每个操作API函数的实现,
创建线性表
/*创建一个线性表*/
/*要创建一个线性表
1.首先给它申请内存空间
2.对线性表成员初始化
3.返回线性表地址*/
sqlink list_create()
{
sqlink L;
//malloc,通过malloc分配一个堆地址
L = (sqlink)malloc(sizeof(sqlist));
if (L == NULL)
{
printf("list malloc fail\n");
return L;
}
//init // 起始地址 填充值 填充长度
memset(L,0,sizeof(sqlist));//memst函数的意思是 从此处的L指针的地址处开始填充,每个位置填充的值为0,填充的长度为sizeof(sqlist)
L->last = -1; //初始化参数last
//return
return L;
}
简单操作函数
只要包括清空线性表,释放线性表内存,判断是否为空,计算线性表长度,显示线性表数据
/*清空数据表*/
/*
*@ret 0--成功 -1--失败
*/
int list_clear(sqlink L)
{
if(L == NULL)
return -1;
memset(L,0,sizeof(sqlist));//memst函数的意思是 从此处的L指针的地址处开始填充,每个位置填充的值为0,填充的长度为sizeof(sqlist)
L->last = -1; //初始化参数last
return 0;
}
/*释放申请的内存*/
int list_free(sqlink L)
{
if(L == NULL)
return -1;
free(L);
L = NULL;
return 0;
}
/*判断线性表是否为空*/
/*para L:list
*@ret 0--成功 -1--失败
*/
int list_empty(sqlink L)
{
if(L->last == -1)
return 1;
else
return 0;
return 0;
}
/*线性表长度*/
int list_length(sqlink L)
{
if(L == NULL)
return -1;
return L->last+1;
}
/*显示线性表数据*/
int list_show(sqlink L)
{
if (L == NULL)
return -1;
if(L->last == -1)
{
printf("list is empty\n");
}
int i;
for(i=0;i<=L->last;i++)
{
printf("%d ",L->data[i]);
}
puts("");/*换行*/
return 0;
}
判断元素是否在线性表中
/*判断一个值是否在线性表L中*/
/*para L:list
*@ret -1-表示值不存在 其他-表示值的位置
*/
int list_locate(sqlink L,data_t value)
{
int i;
for (i = 0; i <= L->last; i++)
{
if(L->data[i] == value)
return i;
}
return -1;
}
线性表中插入元素
/*线性表插入元素*/
int list_insert(sqlink L,data_t value,int pos)
{
int i;
/*检查线性表是否满*/
if(L->last == MAXSIZE)
{
printf("list is full\n");
return -1;
}
/*判断线性表插入位置是否合法,pos->[0,last+1]*/
if(pos < 0 || pos > L->last+1)
{
printf("pos is invalid\n");
return -1;
}
/*移动元素*/
for(i=L->last;i>=2;i--)
{
L->data[i+1] = L->data[i];
}
/*插入新值*/
L->data[pos] = value;
L->last++;
return 0;
}
删除线性表中的元素
/*删除顺序表元素*/
int list_delete(sqlink L,int pos)
{
int i;
/*判断是否非空*/
if(L == NULL)
{
printf("list is full\n");
return -1;
}
/*判断输入的删除位置是否合法*/
if(pos < 0 || pos >= L->last+1)
{
printf("pos is invalid\n");
return -1;
}
/*删除元素,也就是移动元素覆盖*/
for(i=pos+1;i<L->last;i++)
{
L->data[i-1] = L->data[i];
}
/*更新*/
L->last--;
}
求线性表的并集
/*求线性表的并集,比如两个线性表为 L1=[1,4,7] L2=[1 5 8] ---> L_merge = [1 4 7 5 8]*/
int list_merge(sqlink L1,sqlink L2)
{
int i;
int ret;
/*判断L2中的参数是否在L1中存在*/
for(i=0;i<=L2->last;i++)
{
ret = list_locate(L1,L2->data[i]);
if(ret == -1)
{
if(list_insert(L1,L2->data[i],L1->last+1) == -1)
return -1;
}
}
return 0;
}
清除线性表重复元素
/*清除线性表的重复元素*/
int list_purge(sqlink L)
{
int i = 1;
int j;
/*判断表是否空*/
if(L->last == 0)
{
return 0;
}
while (i <= L->last )
{
j = i-1;
while(j >= 0)
{
if(L->data[i] == L->data[j])
{
list_delete(L,i);
break;
}
else
{
j--;
}
}
if(j < 0)
{
i++;
}
}
return 0;
}
以上就是一些关于顺序表的创建等相关操作函数,建议大家可以对照代码理解以下,并且自己动手编写尝试。