C实现线性表

线性表(Linear List)是最常用且最简单的一种数据结构。
github源码
抽象数据类型的定义如下:
ADT List {
数据对象:D={ | ∈ ElemSet, i=1,2,...,n, n≥0 }
数据关系:R1={ <ai-1 ,ai >| ,∈D, i=2,...,n }
基本操作:
InitList( &L )
操作结果:构造一个空的线性表 L 。
DestroyList( &L )
初始条件:线性表 L 已存在。
操作结果:销毁线性表 L 。
ListEmpty( L )
初始条件:线性表L已存在。
操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE。
ListLength( L )
初始条件:线性表 L 已存在。
操作结果:返回 L 中元素个数。
PriorElem( L, cur_e, &pre_e )
初始条件:线性表 L 已存在。
操作结果:若 cur_e 是 L 中的数据元素,则用 pre_e 返回它的前驱,
     否则操作失败,pre_e 无定义。
NextElem( L, cur_e, &next_e )
初始条件:线性表 L 已存在。
操作结果:若 cur_e 是 L 中的数据元素,则用 next_e 返回它的后继,
     否则操作失败,next_e 无定义。
GetElem( L, i, &e )
初始条件:线性表 L 已存在,1≤i≤LengthList(L)。
操作结果:用 e 返回 L 中第 i 个元素的值。
LocateElem( L, e, compare( ) )
初始条件:线性表 L 已存在,compare( ) 是元素判定函数。
操作结果:返回 L 中第1个与 e 满足关系 compare( ) 的元素的位序。
        若这样的元素不存在,则返回值为0。
ListTraverse(L, visit( ))
初始条件:线性表 L 已存在,visit( ) 为元素的访问函数。
操作结果:依次对 L 的每个元素调用函数 visit( )。
       一旦 visit( ) 失败,则操作失败。
ClearList( &L )
初始条件:线性表 L 已存在。
操作结果:将 L 重置为空表。
PutElem( &L, i, &e )
初始条件:线性表L已存在,1≤i≤LengthList(L)。
操作结果:L 中第 i 个元素赋值同 e 的值。
ListInsert( &L, i, e )
初始条件:线性表 L 已存在,1≤i≤LengthList(L)+1。
操作结果:在 L 的第 i 个元素之前插入新的元素 e,L 的长度增1。
ListDelete( &L, i, &e )
初始条件:线性表 L 已存在且非空,1≤i≤LengthList(L)。
操作结果:删除 L 的第 i 个元素,并用 e 返回其值,L 的长度减1。
} ADT List
对上述定义的抽象数据类型线性表,还可以进行一些更复杂的操作,例如取两个线性表的并集、交集和差集。
C实现的代码如下:

#include <stdio.h>
#include <malloc.h>

//线性表

#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10   //线性表存储空间的分配增量(当存储空间不够时要用到)

typedef int ElemType;      //数据元素的类型,假设是int型的

typedef struct{
    ElemType *elem;  //存储空间的基地址
    int length;      //当前线性表的长度
    int listsize;    //当前分配的存储容量
}LinearList;

int init_list(LinearList* list){
    list->elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
    if (!list->elem){
        return -1; //空间分配失败
    }
    list->length = 0; //当前长度
    list->listsize = LIST_INIT_SIZE; //当前分配量
    return 0;
}

void clear_list(LinearList* list){
    list->length = 0; //当前长度
}

void destroy_list(LinearList* list){
    free(list);
}

int list_empty(LinearList* list){
    return (list->length == 0);
}

int list_length(LinearList* list){
    return list->length;
}

void print_list(LinearList* list){
    int i;
    for (i=0; i < list->length; i++){
        printf("%d ", list->elem[i]);
    }
    printf("\n");
}

int locate_elem(LinearList* list, ElemType* x){
    int pos = -1;
    for (int i = 0; i < list->length; i++){
        if (list->elem[i] == *x){
            pos = i;
        }
    }
    return pos;
}

int prior_elem(LinearList* list, ElemType* cur_elem, ElemType* pre_elem){
    int pos = -1;
    pos = locate_elem(list, cur_elem);
    if(pos <= 0) return -1;
    *pre_elem = list->elem[pos-1];
    return 0;
}

int get_elem(LinearList* list, int index, ElemType* e){
    if (index<0 || index >= list->length) return -1;
    *e = list->elem[index];
    return 0;
}

int next_elem(LinearList* list, ElemType* cur_elem, ElemType* next_elem){
    int pos = -1;
    pos = locate_elem(list, cur_elem);
    if(pos == -1 || pos == (list->length - 1)) return -1;
    *next_elem = list->elem[pos+1];
    return 0;
}

int insert_elem(LinearList* list, int index, ElemType* e){
    if (index<0 || index >= list->length) return -1;
    if (list->length >= list->listsize){ //判断存储空间是否够用
        ElemType *newbase = (ElemType *)realloc(list->elem, (list->listsize + LISTINCREMENT)*sizeof(ElemType));
        if (!newbase) return -1;//存储空间分配失败
        list->elem = newbase;//新基址
        list->listsize += LISTINCREMENT;//增加存储容量
    }
    ElemType *q, *p;
    q = &(list->elem[index]); //q为插入位置
    for (p = &(list->elem[list->length - 1]); p >= q; --p){ //从ai到an-1依次后移,注意后移操作要从后往前进行
        *(p + 1) = *p;
    }
    *q = *e;
    ++list->length;
    return 0;
}

int delete_elem(LinearList* list, int index, ElemType* e)
{
    if (index<1 || index > list->length) return -1;
    ElemType *q, *p;
    p = &(list->elem[index]);//p为被删除元素的位置
    *e = *p; //被删除的元素赋值给e
    q = list->elem + list->length - 1;//q指向表尾最后一个元素
    for (++p; p <= q; ++p){ //从p的下一个元素开始依次前移
        *(p - 1) = *p;
    }
    --list->length;
    return 0;
}

int append_elem(LinearList* list,ElemType* e){
    if (list->length >= list->listsize){ //判断存储空间是否够用
        ElemType *newbase = (ElemType *)realloc(list->elem, (list->listsize + LISTINCREMENT)*sizeof(ElemType));
        if (!newbase) return -1;//存储空间分配失败
        list->elem = newbase;//新基址
        list->listsize += LISTINCREMENT;//增加存储容量
    }
    list->elem[list->length] = *e;
    ++list->length;
    return 0;
}

int pop_elem(LinearList* list, ElemType* e){
    if (list_empty(list)) return -1;
    *e = list->elem[list->length - 1];
    --list->length;
    return 0;
}

void union_list(LinearList* list_a, LinearList* list_b, LinearList* list_c){ //并集,C=A∪B
    int i,a_length,b_length;
    ElemType elem;
    a_length = list_length(list_a);
    b_length = list_length(list_b);
    for(i=0;i<a_length;i++){
        get_elem(list_a, i, &elem);
        append_elem(list_c,&elem);
    }   
    for(i=0;i<b_length;i++){
        get_elem(list_b, i, &elem);
        if(locate_elem(list_a, &elem) == -1){
            append_elem(list_c,&elem);
        }
    }
}

void intersect_list(LinearList* list_a, LinearList* list_b, LinearList* list_c){ //交集,C=A∩B
    int i,a_length;
    ElemType elem;
    a_length = list_length(list_a);
    for(i=0;i<a_length;i++){
        get_elem(list_a, i, &elem);
        if(locate_elem(list_b, &elem) != -1){
            append_elem(list_c,&elem);
        }
    }
}

void except_list(LinearList* list_a,LinearList* list_b, LinearList* list_c){ //差集,C=A-B(属于A而不属于B)
    int i,a_length;
    ElemType elem;
    a_length = list_length(list_a);
    for(i=0;i<a_length;i++){
        get_elem(list_a, i, &elem);
        if(locate_elem(list_b, &elem) == -1){
            append_elem(list_c,&elem);
        }
    }
}

测试用例:

int main(void)
{
    int i;
    ElemType elem;
    LinearList *list_a = (LinearList *)malloc(sizeof(LinearList));
    LinearList *list_b = (LinearList *)malloc(sizeof(LinearList));
    LinearList *list_c = (LinearList *)malloc(sizeof(LinearList));
    init_list(list_a);
    init_list(list_b);
    init_list(list_c);
    
    for (i = 0; i < 10; i++){
        append_elem(list_a,&i);
    }
    
    for (i = 0; i < 20; i+=2){
        append_elem(list_b,&i);
    }   
    print_list(list_a);
    print_list(list_b);
    
    pop_elem(list_a, &elem);
    print_list(list_a);
    printf("pop: %d \n",elem);
    
    delete_elem(list_a, 2, &elem);
    print_list(list_a);
    printf("delete: %d \n",elem);
    
    insert_elem(list_a, 2, &elem);
    printf("insert: %d \n",elem);
    print_list(list_a);
    
    get_elem(list_a, 5, &elem);
    printf("get elem at 5: %d \n",elem);
    
    printf("locate : elem %d at %d \n",elem,locate_elem(list_a,&elem));
    
    printf("list_a length : %d \n",list_length(list_a));
    
    print_list(list_a);
    print_list(list_b);
    
    union_list(list_a,list_b,list_c);
    print_list(list_c);
    clear_list(list_c);
    
    intersect_list(list_a,list_b,list_c);
    print_list(list_c);
    clear_list(list_c);
    
    except_list(list_a,list_b,list_c);
    print_list(list_c);
    
    destroy_list(list_a);
    destroy_list(list_b);
    destroy_list(list_c);
    
    return 0;
}

运行结果显示如下:

0 1 2 3 4 5 6 7 8 9 
0 2 4 6 8 10 12 14 16 18 
0 1 2 3 4 5 6 7 8 
pop: 9 
0 1 3 4 5 6 7 8 
delete: 2 
insert: 2 
0 1 2 3 4 5 6 7 8 
get elem at 5: 5 
locate : elem 5 at 5 
list_a length : 9 
0 1 2 3 4 5 6 7 8 
0 2 4 6 8 10 12 14 16 18 
0 1 2 3 4 5 6 7 8 10 12 14 16 18 
0 2 4 6 8 
1 3 5 7
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容