顺序表的类型定义以及基本操作函数

 

引言

本篇文章是我的处女作,主要是我学习清华大学出版社《数据结构》课程顺序表一节的心得体会,主要内容为对于书本上伪代码的详细实现的补充以及学习,如果有任何错误或可以改进之处欢迎各位巨巨指出

 

正文

顺序表作为线性结构的一种,而线性结构的特点是:1.存在唯一的一个被称为“第一个”的元素,同时也存在唯一的一个被称为“最后一个”的元素  2、集合之中的每一个元素均有且仅有一个它的前驱或后继。 由此可以得出,作为一种存储数据的方式,如果了解了某种线性结构的存储方式,即可以通过访问结点的前驱和后继达到访问任何一个结点的效果。

  作为一种线性存储方式,相邻数据元素之间具有一定的序偶关系,序偶关系意为前驱以及后继元素具有着一定的联系。通常这种联系由顺序表的表示结构来看最为直观。假设以a_{i}作为顺序表之中的任何一个元素,其唯一的前驱元素为a_{i-1},其唯一的后继元素为a_{i+1}。其下标i记作a_{i}在顺序表之中的位序。

   由平时学习的经验可知,了解一类数据结构的基本方法,需要从它的基本结构定义以及基本操作进行入手,所谓的基本结构定义为每一个整体的单位数据元,而相关算法,则是以增加修改删除元素为基础的基本操作函数的集合。下面开始书写顺序表的基本结构定义以及基本操作,这也是平时被称作ADT(抽象数据类型) 的表示方法。

   顺序表也可以称作线性表的顺序存储,即使用一组连续的存储单元依次存储线性表的元素,需要注意的是,不同类型的线性表的单位元素大小是不同的,按照已有的认识,表示任何一个元素的存储地址,通过原始的地址加上元素位序与单位元素大小的乘积即可以求出元素的存储地址。两个相邻元素存储位置的关系为:

                                                                           loc_{a_{i+1}}=loc_{a_{i}}+l

位序为i的元素与位序为0的元素存储位置关系为:

                                                                       loc_{a_{i}}=loc_{a_{0}}+(i-1)*l  

 由此,可以看出线性表的顺序存储结构是一种随机存取的存储结构。通常可以用数组来描述该种存储结构,在C语言中可以使用动态存储的一维数组进行表示:

#define LIST_SIZE 100                    //初始分配长度为100
#define LISTINCRESIZE 10                 //存储空间的分配增加量为10
typedef struct 
{
    Elemtype *elem ;                     //存储空间基地址,Elemtype 表示任意的元素
    int length ;                         //当前长度
    int listsize ;                       //当前分配的存储容量,每个元素的单位长度为sizeof(Elemtype)
}Sqlist;

      明确了顺序表的结构定义后,开始了解顺序表的基本操作函数,首先为最基础的线性表构造函数,构造一个长度为length,预分配空间为listsize,当分配空间不足而需要增加大小为存储LISTINCRESIZE个元素的空间,此处每次的增加量定义为10个元素所占有的空间量,顺序表的定义函数如下(在该函数语句中,将抽象类型具体化为int类型):

Sqlist Init(Sqlist &l)
 {
     l.elem = (int *)malloc(LIST_SIZE * sizeof(int));
     l.length = 0;
     l.listsize = LIST_SIZE;
     return l;
 }

     在定义完成了顺序表之后,开始完善顺序表的插入操作,所谓的插入操作,最简单的情形就是在顺序表的第i个元素与i-1个元素之间插入某个元素,而这整体的插入过程可以在一个函数过程之中去实现,在插入元素之后,顺序表的长度同时需要增加一位,而插入位置后一位的元素需要同时向后移位,而对于空表的建立,可将插入函数描述为在第i个元素之前插入某个元素,i从1开始增加至length-1,以下为插入操作的实例,在顺序表的第i个位置之前插入新的元素。

void Insert(Sqlist &l,int i,int e)
 {
     int *q;
     int *p;
     q=&(l.elem[i-1]);                     //q作为一个指针,定义了插入的位置为elem[i-1]
     for(p=&(l.elem[l.length-1]);p>=q;--p) //p作为一个控制for循环的量用于将第i+1位至length-1
     {                                     //的元素向后挪一位
         *(p+1)=*p;
         *q = e;
     }
         ++l.length;
}//在线性顺序表第i个元素插入新的元素 e,i由1开始逐渐增加

  线性表的删除操作与插入操作相反,是使长度为n的线性表转化为长度为n-1的线性表,与插入操作类似,同样地需要移动元素,基本思路如下:1.首先以一个int 类型的指针定位好待删除的元素,其位序记作i ,使用的语句为p=&l.elem[i-1] ,意为取得位序为i的元素的地址  2.用一个int 型变量e转存被删除的元素值 ,语句为 e =*p     3.将该元素位序后的值均向前移动一位,使后位序的元素覆盖前位序的元素 4.线性表的长度减1

void Delete(Sqlist &l,int i,int e)
{
    int *q,*p;
    p=&(l.elem[i-1]);
    e=*p;
    q=l.elem+l.length-1;            //q作为动态数组尾部的节点元素
    for(p++;p<=q;++p)               //位序为i的元素之后的所有元素均向前挪一位
    {
        *(p-1)=*p;
    }
    --l.length;
    cout<<e<<endl;              //长度由length减1
}//以元素e返回被删除的节点元素值

   在顺序表的基本操作之后,还可以进行一些更复杂的操作,例如将两个顺序表归并成一个线性表以及将一个顺序表分割为两个顺序表等其他操作,先行补充几个函数:

1.listLength(Sqlist l) 函数,该函数用于求解线性表的长度,内部定义一个变量length,使用该变量返回顺序表的长度。

int listLength(Sqlist&l)
{
    int length=l.length-1;
    return length;
}

2.Compare(int *e,int *f)函数,该函数用于比较两个顺序表中两个元素的值是否相同,用一个布尔型变量返回比较的结果

bool Compare(int *e,int *f)
{
    if(*e==*f)
    {
        return true;
    }
    else
    {
        return false;
    }
}

另一种情形下的Compare(int *e,int f)函数,用于比较某个顺序表中的元素值与给定的值是否相同,也用布尔型变量返回比较结果

bool Compare(int *e,int f)
{
    if(*e==f)
    {
        return true;
    }
    else
    {
        return false;
    }
}

 3.Locate(Sqlist l,int h)定位函数   该函数用于确定给定元素h在指定顺序表 l 中的位序,由于位序的性质,使得循环变量i由1开始增加,定位函数基本思路如下:1.定义一个循环变量i,用于记录位序,初始化为1  2.定义一个int 类型的指针p,初始化为l.elem,即初始化在elem元素的首位  3.使用while循环以及Compare函数进行元素的定位,当 i 小于顺序表 l 的长度且p指针指向的元素不等于给定元素h时,i 需要增加1,同时p指针也需要向后挪一位  4.当满足任何一个条件时,退出该while循环,进行条件判断.如果此时i小于顺序表的长度 l.length-1,则返回i的值,否则,将值返回为0,即无法在顺序表 l 中定位元素h

int Locate(Sqlist l,int h)
{
    int i=1;
    int *p=l.elem;
    while((i<=l.length-1)&&(Compare(p,h)!=true))
    {
        ++i;
        p++;
    }
    if(i<=l.length-1)
        return i;
    else
        return 0;
}

在补充完毕以上函数后,可以进入顺序表的归并函数 ,顺序表的归并函数基本思路如下:1.将顺序表La与Lb的长度分别确定,再分别定位两个顺序表的首位元素与尾元素  2.建立一个新表Lc,将La与Lb中的元素按大小次序插入顺序表Lc之中 3.若出现La或Lb中任何一个顺序表归并完成而另一个未完成的情形下,将La或Lb剩余的部分插入Lc之中

​
Sqlist unite(Sqlist &la,Sqlist &lb)
{
    int *pa,*pb,*pc;
    int *pa_last,*pb_last;
    pa=la.elem;
    pb=lb.elem;
    Sqlist lc;
    lc.listsize=lc.length=(la.length-1)+(lb.length);
    pc=lc.elem=(int*)malloc(lc.listsize*sizeof(int));
    pa_last=pa+la.length-1;
    pb_last=pb+lb.length-1;
    while(pa<=pa_last&&pb<=pb_last)
    {
        if(*(pa)<=*(pb))
        {
            *pc++=*pa++;
        }
        else
        {
            *pc++=*pb++;
        }
    }
    while(pa<=pa_last)
    {
        *pc++=*pa++;
    }
    while(pb<=pb_last)
    {
        *pc++=*pb++;
    }
    return lc;
}

​

顺序表归并的主体实现函数如下:

int main()
{
    int n;
    cin>>n;
    int num1[n];
    int num2[n];
    Sqlist la;
    Sqlist lb;
    Sqlist lc;
    Init(la);
    Init(lb);
    for(int i=0;i<n;i++)
    {
        cin>>num1[i];
    }
    for(int j=0;j<n;j++)
    {
        cin>>num2[j];
    }
    for(int k=0;k<=n;k++)
    {
        Insert(la,k,num1[k-1]);
    }
    for(int p=0;p<=n;p++)
    {
        Insert(lb,p,num2[p-1]);
    }
    lc=unite(la,lb);
    for(int o=0;o<listLength(lc);o++)
    {
        cout<<lc.elem[o];
    }
    cout<<endl;
    return 0;
}

 

 

  • 19
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值