zoukankan      html  css  js  c++  java
  • 线性表的顺序表示和实现


    /*
    顺序表存储结构容易实现随机存取线性表的第i 个数据元素的操作,但在实现插入、
    删除的操作时要移动大量数据元素,所以,它适用于数据相对稳定的线性表,如职工工资
    表、学生学籍表等。
    c2-1.h 是动态分配的顺序表存储结构,bo2-1.cpp 是基于顺序表的基本操作。由于
    C++函数可重载,故去掉bo2-1.cpp 中算法2.3 等函数名中表示存储类型的后缀_Sq。
    c2-1.h 不采用固定数组作为线性表的存储结构,而采用动态分配的存储结构,这样可以合
    理地利用空间,使长表占用的存储空间多, 短表占用的存储空间少。这些可通过
    bo2-1.cpp 中基本操作函数ListInsert()和图24 清楚看出。
    */

    // c2-1.h 线性表的动态分配顺序存储结构(见图2.1)
    #define LIST_INIT_SIZE 10 // 线性表存储空间的初始分配量
    #define LIST_INCREMENT 2 // 线性表存储空间的分配增量
    struct SqList
    {
    ElemType *elem; // 存储空间基址
    int length; // 当前长度
    int listsize; // 当前分配的存储容量(以sizeof(ElemType)为单位)
    };


    // bo2-1.cpp 顺序表示的线性表(存储结构由c2-1.h定义)的基本操作(12个),包括算法2.3,2.4,2.5,2.6
    void InitList(SqList &L) // 算法2.3
    { // 操作结果:构造一个空的顺序线性表L(见图2.2)
    L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
    if(!L.elem)
    exit(OVERFLOW); // 存储分配失败
    L.length=0; // 空表长度为0
    L.listsize=LIST_INIT_SIZE; // 初始存储容量
    }
    void DestroyList(SqList &L)
    { // 初始条件:顺序线性表L已存在。操作结果:销毁顺序线性表L(见图2.3)
    free(L.elem);
    L.elem=NULL;
    L.length=0;
    L.listsize=0;
    }
    void ClearList(SqList &L)
    { // 初始条件:顺序线性表L已存在。操作结果:将L重置为空表
    L.length=0;
    }
    Status ListEmpty(SqList L)
    { // 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE;否则返回FALSE
    if(L.length==0)
    return TRUE;
    else
    return FALSE;
    }
    int ListLength(SqList L)
    { // 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素的个数
    return L.length;
    }
    Status GetElem(SqList L,int i,ElemType &e)
    { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。操作结果:用e返回L中第i个数据元素的值
    if(i<1||i>L.length)
    return ERROR;
    e=*(L.elem+i-1);
    return OK;
    }
    int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType))
    { // 初始条件:顺序线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
    // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
    // 若这样的数据元素不存在,则返回值为0。算法2.6
    ElemType *p;
    int i=1; // i的初值为第1个元素的位序
    p=L.elem; // p的初值为第1个元素的存储位置
    while(i<=L.length&&!compare(*p++,e))
    ++i;
    if(i<=L.length)
    return i;
    else
    return 0;
    }
    Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e)
    { // 初始条件:顺序线性表L已存在
    // 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱;
    // 否则操作失败,pre_e无定义
    int i=2;
    ElemType *p=L.elem+1;
    while(i<=L.length&&*p!=cur_e)
    {
    p++;
    i++;
    }
    if(i>L.length)
    return INFEASIBLE; // 操作失败
    else
    {
    pre_e=*--p;
    return OK;
    }
    }
    Status NextElem(SqList L,ElemType cur_e,ElemType &next_e)
    { // 初始条件:顺序线性表L已存在
    // 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继;
    // 否则操作失败,next_e无定义
    int i=1;
    ElemType *p=L.elem;
    while(i<L.length&&*p!=cur_e)
    {
    i++;
    p++;
    }
    if(i==L.length)
    return INFEASIBLE; // 操作失败
    else
    {
    next_e=*++p;
    return OK;
    }
    }
    Status ListInsert(SqList &L,int i,ElemType e) // 算法2.4
    { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1
    // 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1(见图2.4)
    ElemType *newbase,*q,*p;
    if(i<1||i>L.length+1) // i值不合法
    return ERROR;
    if(L.length>=L.listsize) // 当前存储空间已满,增加分配
    {
    if(!(newbase=(ElemType *)realloc(L.elem,(L.listsize+LIST_INCREMENT)*sizeof(ElemType))))
    exit(OVERFLOW); // 存储分配失败
    L.elem=newbase; // 新基址
    L.listsize+=LIST_INCREMENT; // 增加存储容量
    }
    q=L.elem+i-1; // q为插入位置
    for(p=L.elem+L.length-1;p>=q;--p) // 插入位置及之后的元素右移
    *(p+1)=*p;
    *q=e; // 插入e
    ++L.length; // 表长增1
    return OK;
    }
    Status ListDelete(SqList &L,int i,ElemType &e) // 算法2.5
    { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
    // 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1(见图2.5)
    ElemType *p,*q;
    if(i<1||i>L.length) // i值不合法
    return ERROR;
    p=L.elem+i-1; // p为被删除元素的位置
    e=*p; // 被删除元素的值赋给e
    q=L.elem+L.length-1; // 表尾元素的位置
    for(++p;p<=q;++p) // 被删除元素之后的元素左移
    *(p-1)=*p;
    L.length--; // 表长减1
    return OK;
    }
    void ListTraverse(SqList L,void(*vi)(ElemType&))
    { // 初始条件:顺序线性表L已存在
    // 操作结果:依次对L的每个数据元素调用函数vi()
    // vi()的形参加′&′,表明可通过调用vi()改变元素的值
    ElemType *p;
    int i;
    p=L.elem;
    for(i=1;i<=L.length;i++)
    vi(*p++);
    printf("
    ");
    }




    // func2-3.cpp 几个常用的函数
    Status equal(ElemType c1,ElemType c2)
    { // 判断是否相等的函数
    if(c1==c2)
    return TRUE;
    else
    return FALSE;
    }
    int comp(ElemType a,ElemType b)
    { // 根据a<、=或>b,分别返回-1、0或1
    if(a==b)
    return 0;
    else
    return (a-b)/abs(a-b);
    }
    void print(ElemType c)
    {
    printf("%d ",c);
    }
    void print2(ElemType c)
    {
    printf("%c ",c);
    }
    void print1(ElemType &c)
    {
    printf("%d ",c);
    }

    // main2-1.cpp 检验bo2-1.cpp的主程序
    #include"c1.h"
    typedef int ElemType;
    #include"c2-1.h"
    #include"bo2-1.cpp"
    #include"func2-3.cpp" // 包括equal()、comp()、print()、print2()和print1()函数
    Status sq(ElemType c1,ElemType c2)
    { // 数据元素判定函数(平方关系),LocateElem()调用的函数
    if(c1==c2*c2)
    return TRUE;
    else
    return FALSE;
    }
    void dbl(ElemType &c)
    { // ListTraverse()调用的另一函数(元素值加倍)
    c*=2;
    }
    void main()
    {
    SqList L;
    ElemType e,e0;
    Status i;
    int j,k;
    InitList(L);
    printf("初始化L后:L.elem=%u L.length=%d L.listsize=%d
    ",L.elem,L.length,L.listsize);
    for(j=1;j<=5;j++)
    i=ListInsert(L,1,j);
    printf("在L的表头依次插入1~5后:*L.elem=");
    for(j=1;j<=5;j++)
    cout<<*(L.elem+j-1)<<"";
    cout<<endl;
    printf("L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize);
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是0:否)
    ",i);
    ClearList(L);
    printf("清空L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize);
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是0:否)
    ",i);
    for(j=1;j<=10;j++)
    ListInsert(L,j,j);
    printf("在L的表尾依次插入1~10后:*L.elem=");
    for(j=1;j<=10;j++)
    cout<<*(L.elem+j-1)<<"";
    cout<<endl;
    printf("L.elem=%u L.length=%d L.listsize=%d
    ",L.elem,L.length,L.listsize);
    ListInsert(L,1,0);
    printf("在L的表头插入0后:*L.elem=");
    for(j=1;j<=ListLength(L);j++) // ListLength(L)为元素个数
    cout<<*(L.elem+j-1)<<"";
    cout<<endl;
    printf("L.elem=%u(有可能改变) L.length=%d(改变) L.listsize=%d(改变)
    ",L.elem,L.length,
    L.listsize);
    GetElem(L,5,e);
    printf("第5个元素的值为%d
    ",e);
    for(j=10;j<=11;j++)
    {
    k=LocateElem(L,j,equal);
    if(k) // k不为0,表明有符合条件的元素,且其位序为k
    printf("第%d个元素的值为%d
    ",k,j);
    else
    printf("没有值为%d的元素
    ",j);
    }
    for(j=3;j<=4;j++)
    {
    k=LocateElem(L,j,sq);
    if(k) // k不为0,表明有符合条件的元素,且其位序为k
    printf("第%d个元素的值为%d的平方
    ",k,j);
    else
    printf("没有值为%d的平方的元素
    ",j);
    }
    for(j=1;j<=2;j++) // 测试头两个数据
    {
    GetElem(L,j,e0); // 把第j个数据赋给e0
    i=PriorElem(L,e0,e); // 求e0的前驱
    if(i==INFEASIBLE)
    printf("元素%d无前驱
    ",e0);
    else
    printf("元素%d的前驱为%d
    ",e0,e);
    }
    for(j=ListLength(L)-1;j<=ListLength(L);j++) // 最后两个数据
    {
    GetElem(L,j,e0); // 把第j个数据赋给e0
    i=NextElem(L,e0,e); // 求e0的后继
    if(i==INFEASIBLE)
    printf("元素%d无后继
    ",e0);
    else
    printf("元素%d的后继为%d
    ",e0,e);
    }
    k=ListLength(L); // k为表长
    for(j=k+1;j>=k;j--)
    {
    i=ListDelete(L,j,e); // 删除第j个数据
    if(i==ERROR)
    printf("删除第%d个元素失败
    ",j);
    else
    printf("删除第%d个元素成功,其值为%d
    ",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L,print1); // 依次对元素调用print1(),输出元素的值
    printf("L的元素值加倍后:");
    ListTraverse(L,dbl); // 依次对元素调用dbl(),元素值乘2
    ListTraverse(L,print1);
    DestroyList(L);
    printf("销毁L后:L.elem=%u L.length=%d L.listsize=%d
    ",L.elem,L.length,L.listsize);
    }

    以下是运行的结果代码:

    /*
    初始化L后:L.elem=3615192 L.length=0 L.listsize=10
    在L的表头依次插入1~5后:*L.elem=54321
    L.elem=3615192 L.length=5 L.listsize=10 L是否空:i=0(1:是0:否)
    清空L后:L.elem=3615192 L.length=0 L.listsize=10 L是否空:i=1(1:是0:否)
    在L的表尾依次插入1~10后:*L.elem=12345678910
    L.elem=3615192 L.length=10 L.listsize=10
    在L的表头插入0后:*L.elem=012345678910
    L.elem=3606792(有可能改变) L.length=11(改变) L.listsize=12(改变)
    第5个元素的值为4
    第11个元素的值为10
    没有值为11的元素
    第10个元素的值为3的平方
    没有值为4的平方的元素
    元素0无前驱
    元素1的前驱为0
    元素9的后继为10
    元素10无后继
    删除第12个元素失败
    删除第11个元素成功,其值为10
    依次输出L的元素:0 1 2 3 4 5 6 7 8 9
    L的元素值加倍后:
    0 2 4 6 8 10 12 14 16 18
    销毁L后:L.elem=0 L.length=0 L.listsize=0
    */


  • 相关阅读:
    CF351A Jeff and Rounding 思维
    CF352B Jeff and Periods 模拟
    CF352A Jeff and Digits
    小B的询问 莫队分块
    小凯的疑惑 数学
    BestCoder Round #80 待填坑
    [SDOI2009]HH的项链 树状数组 BZOJ 1878
    Blocks poj 区间dp
    [USACO5.4]奶牛的电信Telecowmunication 最小割
    数位dp
  • 原文地址:https://www.cnblogs.com/KongkOngL/p/3923439.html
Copyright © 2011-2022 走看看