线性结构的特点:
在数据元素的非空有限集中,
- 存在唯一的一个被称作“第一个”的数据元素;
- 存在唯一的一个被称作“最后一个”的数据元素;
- 除第一个之外,集合中的每个数据元素均只有一个前驱;
- 出最后一个之外,集合中每个数据元素均只有一个后继;
线性表的顺序表示:用一组地址连续的存储单元依次存储线性表的数据元素;
以第一个单元的存储地址作为数据元素的存储位置,称为线性表的起始位置或基地址;
如果每个元素占用 l 个存储单元,第 i 个数据元素的存储位置:LOC(a.i) = LOC(a.1) + (i+1)*l ;
线性表的元素在计算机内以“物理位置相邻”来表示线性表中数据元素之间的逻辑关系;
通常用数组来描述数据结构中顺序存储结构;
顺序存储结构的插入、删除操作时,其时间主要耗费在移动数据元素上;
线性表的操作:
使用数组实现线性表的定义和基本增、删、改、查、遍历等操作;
// 线性表顺序结构及基本操作(头文件)
// file_name: 2_1.h
#ifndef __2_1_H__
#define __2_1_H__
#include
#include
#define Status int
#define ERROR -1
#define OK 0
#define LIST_INIT_SIZE 100 // init size of list
#define LISTINCREMENT 10 // step of increment
typedef int ElemType; // type of elem
typedef struct{
ElemType *elem; // base addr
int length; // current len
int listsize; // size of list
}SqList;
// - Compare
Status Compare(ElemType cur_e, ElemType e);
// - Visit
void Visit(ElemType e);
// - 初始化
Status InitList(SqList *l);
// - 销毁
void DestroyList(SqList *l);
// - 清空
void ClearList(SqList *l);
// - 判空
Status ListEmpty(SqList l);
// - 计算长度
int ListLength(SqList l);
// - 取某元素
Status GetElem(SqList l, int i, ElemType *e);
// - 返回首个与给出元素满足Compare关系的位序
int LocateElem(SqList l, ElemType e, Status(Compare)(ElemType, ElemType));
// - 返回元素前驱
Status PriorElem(SqList l, ElemType cur_e, ElemType *pre_e);
// - 返回元素后继
Status NextElem(SqList l, ElemType cur_e, ElemType *next_e);
// - 插入
Status ListInsert(SqList *l, int i, ElemType e);
// - 删除
Status ListDelete(SqList *l, int i, ElemType *e);
// - 遍历
Status ListTraverse(SqList l, void(Visit)(ElemType));
#endif // __2_1_H__
// 线性表顺序结构及基本操作(源文件)
// file_name: 2_1.c
#include "2_1.h"
// - Compare
Status Compare(ElemType cur_e, ElemType e){
if(cur_e == e){
return OK;
}
return ERROR;
}
// - Visit
void Visit(ElemType e){
printf("%d ", e);
}
// - 初始化
Status InitList(SqList *l){
l->elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if(!(l->elem)){
return ERROR;
}
l->length = 0;
l->listsize = LIST_INIT_SIZE;
return OK;
}
// - 销毁
void DestroyList(SqList *l){
free(l->elem);
l->elem = NULL;
l->length = 0;
l->listsize = 0;
}
// - 清空
void ClearList(SqList *l){
l->length = 0;
}
// - 判空
Status ListEmpty(SqList l){
return (l.length==0) ? OK : ERROR;
}
// - 计算长度
int ListLength(SqList l){
return l.length;
}
// - 取某元素
Status GetElem(SqList l, int i, ElemType *e){
if(i<1 || i>l.length){
return ERROR;
}else{
(*e) = l.elem[i-1];
}
return OK;
}
// - 返回首个与给出元素满足Compare关系的位序
int LocateElem(SqList l, ElemType e, Status(Compare)(ElemType, ElemType)){
int i = 1;
for(i=1; i<=l.length; i++){
if(OK == Compare(l.elem[i-1], e)){
return i;
}
}
return 0;
}
// - 返回元素前驱
Status PriorElem(SqList l, ElemType cur_e, ElemType *pre_e){
if(l.elem[0] != cur_e){
int i = 1;
for(i=1; i<l.length; i++){
if(l.elem[i] == cur_e){
*pre_e = l.elem[i-1];
return OK;
}
}
}
return ERROR;
}
// - 返回元素后继
Status NextElem(SqList l, ElemType cur_e, ElemType *next_e){
int i = 0;
for(i=0; i<l.length-1; i++){
if(l.elem[i] == cur_e){
*next_e = l.elem[i+1];
return OK;
}
}
return ERROR;
}
// - 插入
Status ListInsert(SqList *l, int i, ElemType e){
if(i<1 || i>l->length+1){
return ERROR;
}
ElemType *new_base;
if(l->length >= l->listsize){
// realloc
new_base = (ElemType *)realloc(l->elem, (l->length+LISTINCREMENT)*sizeof(ElemType));
if(NULL == new_base){
return ERROR;
}
l->elem = new_base;
l->listsize += LISTINCREMENT;
}
// move
int j;
for(j=l->length; j>=i; j--){
l->elem[j] = l->elem[j-1];
}
// insert
l->elem[i-1] = e;
l->length++;
return OK;
}
// - 删除
Status ListDelete(SqList *l, int i, ElemType *e){
if(i<1 || i>l->length){
return ERROR;
}
// get value
*e = l->elem[i-1];
// move
int j;
for(j=i; j<l->length; j++){
l->elem[j-1] = l->elem[j];
}
// insert
l->length--;
return OK;
}
// - 遍历
Status ListTraverse(SqList l, void(Visit)(ElemType)){
int i = 0;
printf("------ visit ------\r\n");
for(i=0; i<l.length; i++){
Visit(l.elem[i]);
}
printf("\r\n---- visit end ----\r\n");
return OK;
}
// 线性表顺序结构及基本操作(测试文件)
// file_name: 2_1_test.c
#include "2_1.h"
int main(){
printf("------------------------------test-------------------------------\r\n");
SqList sl;
int i = 0;
ElemType e = 0;
ElemType pre_e, next_e;
// init
if(OK == InitList(&sl)){
printf("init OK!\r\n");
}else{
printf("init failed.\r\n");
return 0;
}
// insert
for(i=1; i<20; i++){
if(OK == ListInsert(&sl, i, (ElemType)i)){
printf("insert %d ok.\r\n", i);
}else{
printf("insert %d failed.\r\n", i);
}
}
// traverse
if(OK == ListTraverse(sl, Visit)){
printf("traverse over.\r\n");
}else{
printf("traverse failed.\r\n");
}
// length
printf("the length of list: %d\r\n", ListLength(sl));
// delete
i = 5;
if(OK == ListDelete(&sl, i, &e)){
printf("del the %d elem, value is: %d\r\n", i, e);
}else{
printf("del the %d elem failed.\r\n", i);
}
// traverse
if(OK == ListTraverse(sl, Visit)){
printf("traverse over.\r\n");
}else{
printf("traverse failed.\r\n");
}
// length
printf("the length of list: %d\r\n", ListLength(sl));
// getelem
i = 3;
e = 0;
if(OK == GetElem(sl, i, &e)){
printf("get elem OK, the %d elem is: %d\r\n", i, e);
}else{
printf("get elem failed.\r\n");
}
// locateElem
e = 7;
int ret = LocateElem(sl, e, Compare);
if(ret > 0){
printf("the elem of %d, order is: %d\r\n", e, ret);
}else{
printf("the elem not exist in list.\r\n");
}
// prior
e = 3;
if(OK == PriorElem(sl, e, &pre_e)){
printf("the pre of %d is: %d\r\n", e, pre_e);
}else{
printf("find the pre of %d failed.\r\n", e);
}
// next
e = 3;
if(OK == NextElem(sl, e, &next_e)){
printf("the next of %d is: %d\r\n", e, next_e);
}else{
printf("find the next of %d failed.\r\n", e);
}
// clear
ClearList(&sl);
// empty
if(OK == ListEmpty(sl)){
printf("now the list is empty.\r\n");
}else{
// length
printf("the length of list: %d\r\n", ListLength(sl));
}
// destroy
DestroyList(&sl);
printf("------------------------------end--------------------------------\r\n");
return 0;
}
# 结果输出
ubuntu@ubuntu:~/work/c/algo$ gcc 2_1_test.c 2_1.c
ubuntu@ubuntu:~/work/c/algo$ ./a.out
------------------------------test-------------------------------
init OK!
insert 1 ok.
insert 2 ok.
insert 3 ok.
insert 4 ok.
insert 5 ok.
insert 6 ok.
insert 7 ok.
insert 8 ok.
insert 9 ok.
insert 10 ok.
insert 11 ok.
insert 12 ok.
insert 13 ok.
insert 14 ok.
insert 15 ok.
insert 16 ok.
insert 17 ok.
insert 18 ok.
insert 19 ok.
------ visit ------
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
---- visit end ----
traverse over.
the length of list: 19
del the 5 elem, value is: 5
------ visit ------
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19
---- visit end ----
traverse over.
the length of list: 18
get elem OK, the 3 elem is: 3
the elem of 7, order is: 6
the pre of 3 is: 2
the next of 3 is: 4
now the list is empty.
------------------------------end--------------------------------
ubuntu@ubuntu:~/work/c/algo$
思路:循环遍历 b表元素,判断是否已经在 a中出现过,1.出现过则跳过,2.未出现则插入 a表尾部;
// 线性表扩展
#include "2_1.h"
// union
Status Union(SqList *sl_a, SqList *sl_b){
int i = 0;
ElemType e;
int p = sl_a->length;
for(i=1; i<=sl_b->length; i++){
if(OK == GetElem(*sl_b, i, &e)){
// compare
if(LocateElem(*sl_a, e, Compare) <= 0){
// insert
if(OK == ListInsert(sl_a, ++p, e)){
printf("insert list OK.\r\n");
}else{
printf("insert list failed.\r\n");
}
}else{
printf("the elem:%d has already in list.\r\n", e);
}
}else{
printf("get elem at pos:%d failed.\r\n", i);
}
}
return OK;
}
int main(void){
int i = 0;
int ret = 0;
SqList sl_a, sl_b;
ElemType arr_a[5] = {8, 4, 2, 1, 9};
ElemType arr_b[9] = {8, 3, 0, 5, 6, 7, 9, 10, 11};
// 0. init
ret = InitList(&sl_a);
if(OK == ret){
printf("init list OK.\r\n");
}else{
printf("init list failed.\r\n");
}
ret = InitList(&sl_b);
if(OK == ret){
printf("init list OK.\r\n");
}else{
printf("init list failed.\r\n");
}
// 1. insert
int len_a, len_b;
len_a = sizeof(arr_a)/sizeof(ElemType);
len_b = sizeof(arr_b)/sizeof(ElemType);
for(i=0; i<len_a; i++){
if(OK == ListInsert(&sl_a, i+1, arr_a[i])){
printf("insert %d to list OK.\r\n", arr_a[i]);
}else{
printf("insert %d to list failed.\r\n", arr_b[i]);
}
}
for(i=0; i<len_b; i++){
if(OK == ListInsert(&sl_b, i+1, arr_b[i])){
printf("insert %d to list OK.\r\n", arr_b[i]);
}else{
printf("insert %d to list failed.\r\n", arr_b[i]);
}
}
// 2. print
ListTraverse(sl_a, Visit);
ListTraverse(sl_b, Visit);
// 3. union
if(OK == Union(&sl_a, &sl_b)){
printf("union OK.\r\n");
}else{
printf("union failed.\r\n");
}
// 4. print
ListTraverse(sl_a, Visit);
return 0;
}
# 输出结果
ubuntu@ubuntu:~/work/c/algo$ gcc 2_2.c 2_1.c
ubuntu@ubuntu:~/work/c/algo$ ./a.out
init list OK.
init list OK.
insert 8 to list OK.
insert 4 to list OK.
insert 2 to list OK.
insert 1 to list OK.
insert 9 to list OK.
insert 8 to list OK.
insert 3 to list OK.
insert 0 to list OK.
insert 5 to list OK.
insert 6 to list OK.
insert 7 to list OK.
insert 9 to list OK.
insert 10 to list OK.
insert 11 to list OK.
------ visit ------
8 4 2 1 9
---- visit end ----
------ visit ------
8 3 0 5 6 7 9 10 11
---- visit end ----
the elem:8 has already in list.
insert list OK.
insert list OK.
insert list OK.
insert list OK.
insert list OK.
the elem:9 has already in list.
insert list OK.
insert list OK.
union OK.
------ visit ------
8 4 2 1 9 3 0 5 6 7 10 11
---- visit end ----
ubuntu@ubuntu:~/work/c/algo$
思路:因为 a、b 是已经排序的顺序表,只要相互比较取数放到 c 中即可;
相互比较分为两种情况:元素和后继元素比较;元素和另一个表中定位元素比较;
此时只需要记录当前位置即可;
// 线性表合并
#include "2_1.h"
// merge
Status MergeList(SqList *sl_a, SqList *sl_b, SqList *sl_c){
ElemType e_a, e_b, e_c;
int i = 0;
int cur_a = 1;
int cur_b = 1;
int len_a = sl_a->length;
int len_b = sl_b->length;
int len_c = len_a + len_b;
for(i=1; i<=len_c; i++){
if(cur_a<=len_a && cur_b<=len_b){
GetElem(*sl_a, cur_a, &e_a);
GetElem(*sl_b, cur_b, &e_b);
if(e_a > e_b){
e_c = e_b;
cur_b++;
}else{
e_c = e_a;
cur_a++;
}
}else{
if(cur_a <= len_a){
GetElem(*sl_a, cur_a, &e_a);
e_c = e_a;
cur_a++;
}
if(cur_b <= len_b){
GetElem(*sl_b, cur_b, &e_b);
e_c = e_b;
cur_b++;
}
}
if(OK == ListInsert(sl_c, i, e_c)){
printf("insert %d to list_c OK.\r\n", e_c);
}else{
printf("insert %d to list_c Failed.\r\n", e_c);
}
}
return OK;
}
int main(void){
int i = 0;
int ret = 0;
SqList sl_a, sl_b, sl_c;
ElemType arr_a[8] = {1, 3, 5, 6, 6, 9, 22, 33};
ElemType arr_b[12] = {2, 3, 3, 5, 6, 7, 7, 9, 10, 11, 12, 32};
// 0. init
ret = InitList(&sl_a);
if(OK == ret){
printf("init list OK.\r\n");
}else{
printf("init list failed.\r\n");
}
ret = InitList(&sl_b);
if(OK == ret){
printf("init list OK.\r\n");
}else{
printf("init list failed.\r\n");
}
ret = InitList(&sl_c);
if(OK == ret){
printf("init list OK.\r\n");
}else{
printf("init list failed.\r\n");
}
// 1. insert
int len_a, len_b;
len_a = sizeof(arr_a)/sizeof(ElemType);
len_b = sizeof(arr_b)/sizeof(ElemType);
for(i=0; i<len_a; i++){
if(OK == ListInsert(&sl_a, i+1, arr_a[i])){
printf("insert %d to list OK.\r\n", arr_a[i]);
}else{
printf("insert %d to list failed.\r\n", arr_b[i]);
}
}
for(i=0; i<len_b; i++){
if(OK == ListInsert(&sl_b, i+1, arr_b[i])){
printf("insert %d to list OK.\r\n", arr_b[i]);
}else{
printf("insert %d to list failed.\r\n", arr_b[i]);
}
}
// 2. print
ListTraverse(sl_a, Visit);
ListTraverse(sl_b, Visit);
ListTraverse(sl_c, Visit);
// 3. merge
if(OK == MergeList(&sl_a, &sl_b, &sl_c)){
printf("union OK.\r\n");
}else{
printf("union failed.\r\n");
}
// 4. print
ListTraverse(sl_c, Visit);
return 0;
}
# 输出结果
ubuntu@ubuntu:~/work/c/algo$ gcc 2_3.c 2_1.c
ubuntu@ubuntu:~/work/c/algo$ ./a.out
init list OK.
init list OK.
init list OK.
insert 1 to list OK.
insert 3 to list OK.
insert 5 to list OK.
insert 6 to list OK.
insert 6 to list OK.
insert 9 to list OK.
insert 22 to list OK.
insert 33 to list OK.
insert 2 to list OK.
insert 3 to list OK.
insert 3 to list OK.
insert 5 to list OK.
insert 6 to list OK.
insert 7 to list OK.
insert 7 to list OK.
insert 9 to list OK.
insert 10 to list OK.
insert 11 to list OK.
insert 12 to list OK.
insert 32 to list OK.
------ visit ------
1 3 5 6 6 9 22 33
---- visit end ----
------ visit ------
2 3 3 5 6 7 7 9 10 11 12 32
---- visit end ----
------ visit ------
---- visit end ----
insert 1 to list_c OK.
insert 2 to list_c OK.
insert 3 to list_c OK.
insert 3 to list_c OK.
insert 3 to list_c OK.
insert 5 to list_c OK.
insert 5 to list_c OK.
insert 6 to list_c OK.
insert 6 to list_c OK.
insert 6 to list_c OK.
insert 7 to list_c OK.
insert 7 to list_c OK.
insert 9 to list_c OK.
insert 9 to list_c OK.
insert 10 to list_c OK.
insert 11 to list_c OK.
insert 12 to list_c OK.
insert 22 to list_c OK.
insert 32 to list_c OK.
insert 33 to list_c OK.
union OK.
------ visit ------
1 2 3 3 3 5 5 6 6 6 7 7 9 9 10 11 12 22 32 33
---- visit end ----
ubuntu@ubuntu:~/work/c/algo$
—— 2018-12-03 ——