线性表是包含若干数据元素的一个线性序列
记为:L=(a0,…ai-1,ai,ai+1,…an-1)
L
为表名,ai(0
?
\leqslant
?i
?
\leqslant
?n-1)为数据元素;n
为表长,n>0
是,线性表L为非空表,否则为空表。
线性表L可用二元组形式描述:L=(D,R)
即线性表L包含数据元素集合D和关系集合R
举个例子:
设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>}
线性表的特征
- 对非空表,a0是表头,无前驱;
- an-1是表尾,无后继;
- 其它的每个元素ai有且仅有一个直接前驱ai-1和一个直接后继ai+1。
其实就是上图的表示方式
将线性表L=(a~0~,....a~i-1~,a~i~,a~i+1~,...a~n-1~)
中各元素依次存储在计算机一片连续的存储空间。
则假设Loc(a~i~)
为a~i~
的地址,Loc(a0)=b,则有:Loc(a~i~) = b + i * d
顺序存储的特点:
- 优点
- 逻辑上相邻的元素ai,ai+1,其存储位置也相邻
- 对数据元素ai的存取为随机存取或按地址存取
- 存储密度高
- 存储密度D = (数据结构中元素所占存储空间)/(整个数据结构所占空间)
- 缺点
看问题应用场景,其实任何方式都有优缺点都有其应用场景,只有相对较好的解决方案,没有正确的解决方案!
顺序存储的定义方式
在C语言中,可借助于一维数组类型来描述。
线性表的顺序存储结构
#define N 100
typedef int data_t;
typedef struct{
data_t data[n];
int last;
}sqlist,*sqlink;
代码的写作规范
一般的写作包含三部分内容sqlist.h
、sqlist.c
、test.c
sqlist.h
包含定义、运算sqlist.c
包含函数的接口实现
代码分层的原因:
其中外包公司用的时候为了保护公司核心资产所以只会给.h和编译好的.s.o
。所以.h
文件一般暴露接口定义和基本的数据结构定义。
所以可以使用两种方式编译:
gcc -c test.c sqlist.c
gcc *.o -o a.out
gcc *.c -o a.out
所以给外包公司汇编好的.o
即可,头文件也需要给到就完事了。
线性表的基本运算
建立一个空表:list_create(L)
sqlink list_create(){
sqlink L;
L = (sqlink)malloc(sizeof(sqlist));
if ( L == NULL){
printf("list malloc failed\n");
return L;
}
memset(L, 0, sizeof(sqlist));
L->last = -1;
return L;
}
置空表:list_clear(L)
int list_clear(sqlink L){
if(L == NULL)
return -1;
memset(L, 0, sizeof(sqlist));
L->last = -1;
return 0;
}
判空:list_empty(L) 空返回1
,非空为0
int list_empty(sqlink L){
if (L == NULL)
return -1;
if (L->last == -1)
return 1;
else
return 0;
}
求表长:length(L)
int list_length(sqlink L){
if (L == NULL)
return -1;
return (L->last + 1);
}
插入:Insert(L,x,i)将元素x插入到表L中第i个元素a~i~
之前,且表长+1
其中的三个问题:
last < (N - 1)
-
0
?
p
o
s
?
l
a
s
t
+
1
0 \leqslant pos \leqslant last+1
0?pos?last+1
- 如果在
last+1
插入不需要移动,否则从后往前依次移动。
int list_insert(sqlink L, data_t value, int pos){
int i;
if (L == NULL)
printf("list is invalid\n");
if (L->last == N-1){
printf("list is full\n");
return -1;
}
if ( pos < 0 || pos > L->last+1){
printf("Pos is invalid\n");
return -1;
}
for (i = L->last; i >= pos; i--){
L->data[i+1] = L->data[i];
}
L->data[pos] = value;
L->last ++;
return 0;
}
释放空间:list_free(sqlink L);
int list_free(sqlink L){
if (L == NULL)
return -1;
free(L);
L = NULL;
return 0;
}
显示所有元素:list_show(sqlink L);
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;
}
显示所有元素:list_delete(sqlink L, int pos);
int list_delete(sqlink L, int pos){
if (L == NULL){
printf("list is invalid\n");
return -1;
}
if (L->last == -1){
printf("list is empty\n");
return -1;
}
if (pos < 0 || pos > L->last){
printf("delete pos is invalid\n");
return -1;
}
for (int i = pos + 1; i <= L->last; i++){
L->data[i-1] = L->data[i];
}
L->last --;
return 0;
}
合并链表:list_merge(sqlink L1, sqlink L2)
int list_merge(sqlink L1, sqlink L2){
int i = 0;
while (i <= L2->last){
int ret = list_locate(L1, L2->data[i]);
if (ret == -1){
if(list_insert(L1, L2->data[i], L1->last + 1) == -1)
return -1;
}
++i;
}
return 0;
}
删除线性表中重复的元素:list_purge(sqlink L)
int list_purge(sqlink L){
int i = 1, 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;
}