目录
1、设线性表 L=(a0,a1, ……,an-1),对 L的基本运算有:
(1)建立一个空表:sqlink list_create()。
(2)置空表:data_t list_clear(sqlink L)
(3)判断表是否为空:data_t list_empty (sqlink L)。
(4)求表长:data_t length (sqlink L)
(5)取表中某个元素的下标:data_t list_locate(sqlink L,data_t value)
(6)取表中某个元素的值:data_t list_getlist(sqlink L,int i)
(7)插入:data_t list_insert(sqlink L,data_t value,int i)。
(8)删除:int list_delete(sqlink L,int i)。
(9)释放内存:int list_free(sqlink L)
(10)打印:int list_show(sqlink L)。
(11)线性表去重 :int list_purge(sqlink L)
(12)线性表合并 :int list_merge(sqlink L1,sqlink L2)
一、线性表定义、特点
1、定义:线性表是包含若干数据元素的一个线性序列记为:
L=(a0, ...... ai-1, ai, ai+1 ...... an-1)L为表名
ai (0≤i≤n-1)为数据元素;
n为表长,n>0 时,线性表L为非空表,否则为空表。
线性表:L可用二元组形式描述:
L=(D,R)
即线性表L包含数据元素集合D和关系集合R
D={ai | ai ∈datatype, i = 0,1,2 -----n-1,n≥0}
R={<ai , ai+1> | ai , ai+1 ∈D,0≤i≤n-2}
- 关系符<ai,ai+1>在这里称为有序对
- 表示任意相邻的两个元素之间的一种先后次序关系
- ai是ai+1的直接前驱,ai+1是ai的直接后继
例如:
设有一个顺序表L={1,2,3,4,5,6};他们的关系如图:
①-②-③-④-⑤-⑥
使用二元组描述L=(D,R),则
D = {1,2,3,4,5,6}{n=6}
R = {<1,2>,<2,3>,<3,4>,<4,5>,<5,6>}
2、特点:
- 对非空表,a0是表头,无前驱;
- an-1是表尾,无后继;
- 其它的每个元素ai有且仅有一个直接前驱ai-1和一个直接后继ai+1。
二、顺序存储结构
若将线性表L=(a0,a1,.....an-1)中各元素依次存储于计算机一片连续的存储空间。
设Loc(ai)为ai的地址,Loc(a0),每个元素占d个单元则:
Loc(ai)= b+i*d
b: | a0 |
b+d: | a1 |
b+i*d: | ai |
... | ... |
b+(n-1)*d: | an-1 |
1、顺序存储结构的特点
(1)逻辑上相邻的元素 ai, ai+1,其存储位置也是相邻的。对数据元素ai的存取为随机存取或按地址存取存储密度高存储密度D=(数据结构中元素所占存储空间)/(整个数据结构所占空间)
(2)顺序存储结构的不足:对表的插入和删除等运算的时间复杂度较差。适合查找对,插入删除少的情况
2、存储结构
在C语言中,可借助于一维数组类型来描述线性表的顺序存储结构
#define N 100
typedef int data_t;
typedef struct
{
data_t data[N]; //表的存储空间
int last; //存放数组最后一个元素的下标
}sqlist,*sqlink;
a0 |
... |
ai |
.., |
last |
三、线性表的基本运算
1、设线性表 L=(a0,a1, ……,an-1),对 L的基本运算有:
(1)建立一个空表
(2)置空表:
(3)判断表是否为空
(4)求表长
(5)取表中某个元素
(6)定位运算,确定元素x在表L中的位置(或序号)
(7)插入
(8)删除:list_delete(L,i)。删除表L中第i个元素ai,且表长减1, 要求0≤i≤n-1
(9)释放表内存
(10)表打印
(12)线性表去重
(13)线性表合并
2、算法实现
思路:一般编程会写4个文件
- sqlist.h //数据结构定义,运算
- sqlist.c // 运算的实现
- test.c //根据应用提供接口
- makefile //因为gcc 编译每次需要敲很多命令,通过make可以更便捷,需要了解可参考
-------------->makefile管理工具
这样布局的好处:
- 结构清晰
- 软件复用(给自己用,给同事,外包,包括.h和.o文件,源码自己保留)
sqlist.h文件展示
#define N 100
typedef int data_t;
typedef struct{
data_t data[N];
int last;
}sqlist, *sqlink;
sqlink list_create();
int list_clear(sqlink L);
int list_isempty(sqlink L);
int list_length(sqlink L);
int list_locate(sqlink L,data_t value);
data_t list_getlist(sqlink L,int i);
int list_insert(sqlink L,data_t value,int i);
int list_delete(sqlink L,int i);
int list_free(sqlink L);
int list_show(sqlink L);
int list_purge(sqlink L);
int list_merge(sqlink L1,sqlink L2);
(1)建立一个空表:sqlink list_create()。
函数类型:指针函数,若需要其他数据结构,方便用户通过指针切换。
参数:无
返回值:指针
描述:首先创建一个结构体指针,对指针分配内存空间(malloc),若分配成功,对数组清零操作(memset),下标last=-1代表空。
#include<stdio.h>
#include "sqlist.h"
#include <stdlib.h>
#include <string.h>
sqlink list_create(){
sqlink L;
L = (sqlink)malloc(sizeof(sqlist));
if( L == NULL)
{
printf("sqlist malloc failed\n");
return L;
}
L = memset(L,0,sizeof(sqlist));
L->last = -1;
printf("sqlist is create\n");
return L;
}
(2)置空表:data_t list_clear(sqlink L)
函数类型:int型
参数:指针
返回值:置空成功返回0,输入函数为空返回-1
描述:判断输入函数是否为空,不为空清0数组,下标last置-1。
int list_clear(sqlink L){
//empty
if(L == NULL)
{
printf("list is empty\n");
return -1;
}
//clear
L = memset(L,0,sizeof(sqlist));
L->last = -1;
return 0;
}
(3)判断表是否为空:data_t list_empty (sqlink L)。
函数类型:int型
参数:指针
返回值:若表为空,返回值为1 , 否则返回 0
描述:判下标last是否为-1。
int list_isempty(sqlink L){
//empty
if(L->last == -1)
{
printf("list is empty\n");
return 1;
}
printf("list is not empty\n");
return 0;
}
(4)求表长:data_t length (sqlink L)
函数类型:int型
参数:指针
返回值:表长度
描述:不为空,返回下标last+1。数组是从0开始,所以要加1。
int list_length(sqlink L){
if( L == NULL){
printf("list is NULL\n");
return -1;
}
return L->last+1;
}
(5)取表中某个元素的下标:data_t list_locate(sqlink L,data_t value)
函数类型:int型
参数1:指针
参数2:数据值
返回值:找到返回下标,没找到返回-1
描述:遍历是否等于value,找到返回
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;
}
(6)取表中某个元素的值:data_t list_getlist(sqlink L,int i)
函数类型:data_t
参数1:指针
参数2:下标
返回值:找到数据,没找到返回-1
描述:取数组的值,增加了参数检查判断。
data_t list_getlist(sqlink L,int i){
if (L == NULL){
return -1;
}
if (L->last == -1)
printf("list is empty");
return -1;
if(i<0 || i>L->last){
printf("out of range\n");
return -1;
}
return L->data[i];
}
(7)插入:data_t list_insert(sqlink L,data_t value,int i)。
函数类型:int型
参数1:指针
参数2:数据值
参数3:位置
返回值:成功返回0,失败返回-1
描述:把ch[i]到ch[last]的数据整体移动到ch[i+1]到ch[last+1]的位置,再赋值ch[i] =value。要求表长+1。
data_t list_insert(sqlink L,data_t value,int i){
int j;
//full
if(L->last == N-1)
{
printf("list is full\n");
return -1;
}
//check para [0,last+1]
if( i < 0 || i > L->last + 1){
printf("i is out of range\n");
return -1;
}
//move [i,last+1]
for(j = L->last; j >= i; j--){
L->data[j+1] = L->data[j];
}
L->data[i] = value;
L->last++;
printf("Last:%d ",L->last);
return 0;
}
(8)删除:int list_delete(sqlink L,int i)。
函数类型:int型
参数1:指针
参数2:位置 (范围校验)
返回值:成功返回0,失败返回-1
描述:删除表L中第i个元素。把ch[i+1]到ch[last]的数据整体移动到ch[i]到ch[last-1]的位置。要求表长-1。
int list_delete(sqlink L,int i){
int j;
//empty
if(L->last == -1)
{
printf("list is empty\n");
return -1;
}
//check para [0,last]
if( i < 0 || i > L->last){
printf("i is out of range\n");
return -1;
}
//move [i+1,last)
for(j = i+1 ; j <= L->last; j++){
L->data[j-1] = L->data[j];
}
L->last --;
return 0;
}
(9)释放内存:int list_free(sqlink L)
略
int list_free(sqlink L){
if(L==NULL)
return -1;
free(L);
L=NULL;
return 0;
}
(10)打印:int list_show(sqlink L)。
函数类型:int型
参数1:指针
返回值:成功返回0,失败返回-1
描述:遍历数组
int list_show(sqlink L){
int i;
if(L == NULL){
return -1;
}
if(L->last == -1){
printf("list is empty\n");
}
for(i = 0; i <= L->last; i++){
printf("%d ",L->data[i]);
}
puts("");
return 0;
}
(11)线性表去重 :int list_purge(sqlink L)
函数类型:int型
参数1:指针
返回值:成功返回0,失败返回-1
描述:定义两个下标i和j,i指向1,j指向i-1。循环判断i之前的数据是否与i相同,若相同删除数据,若不相同,i++。
int list_purge(sqlink L){
int i=1,j;
//empty
if(list_isempty(L)){
return -1;
}
//only onei
if(L->last ==0)
return -1;
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++;
}
list_show(L);
return 0;
}
(12)线性表合并 :int list_merge(sqlink L1,sqlink L2)
函数类型:int型
参数1:表1指针
参数2:表2指针
返回值:成功返回0,失败返回-1
描述:遍历表2的值,逐个插入到表1尾部。
int list_merge(sqlink L1,sqlink L2){
//check
if(L1 == NULL || L2 == NULL){
return -1;
}
if(L1->last+1+L2->last+1 >N){
printf("full\n");
return -1;
}
int i = 0;
while(i <= L2->last){
if(list_locate(L1,L2->data[i]) == -1){ //判断是否重复数据
if(list_insert(L1,L2->data[i],L1->last+1) == -1)
return -1;
}
i++;
}
list_free(L2);
return 0;
}
实现创建test.c调用接口
#include<stdio.h>
#include "sqlist.h"
int main(char argc,char *argv[]){
sqlink L;
//create
L = list_create();
//insert
list_insert(L,1,0);
list_insert(L,1,0);
list_insert(L,2,0);
list_insert(L,2,0);
list_insert(L,4,0);
list_insert(L,5,0);
//lengh
printf("length:%d\n",list_length(L));
list_insert(L,6,list_length(L));
//show
list_show(L);
//delete
list_delete(L,0);
list_show(L);
//getlist
list_getlist(L,5);
//purge
list_purge(L);
//merge
sqlink L2;
L2 = list_create();
list_insert(L,10,0);
list_insert(L,11,1);
list_insert(L,12,2);
list_insert(L,13,3);
list_show(L2);
list_merge(L,L2);
list_show(L);
return 0;
}
创建makefile方便编译
OBJS= sqlist.o test.o
CC= gcc
CFLAGS= -c
test:test.o sqlist.o
.PYONY:clean
clean:
rm *.o test
总结:
线性表的顺序存储结构有存储密度高及能够随机存取等优点,但存在以下不足:
- 要求系统提供一片较大的连续存储空间。
- 插入、删除等运算耗时,且存在元素在存储器中成片移动的现象。