数据结构——线性表(二)

来源:互联网 发布:北京域名备案的时间 编辑:程序博客网 时间:2024/05/27 01:10

        上一篇博客写道,对于用顺序存储结构来实现的线性表来说,我们很容易就能实现数据元素的查找,可是对于插入和删除操作来说就会变得有些麻烦。于是,我们即将介绍一种新的存储方式——链式存储。线性表的链式存储结构的特点是用一组任意的存储单元来存放线性表中的数据元素,这些数据元素只要求逻辑上的相邻而不一定要求物理意义上的相邻。为了表示两数据元素之间的逻辑相邻,我们用一个指针来连接一个数据元素和它的后一个数据元素。因此,一个数据元素拥有了两个信息,一个是数据元素本身的信息,我们称之为数据域。另一个是储存这个数据元素的后驱(后一个数据元素)的存储位置,我们称之为指针域,这两个信息组合起来就是这个数据元素的映射,我们称之为结点。

        我们来看看链式存储的存储结构

typedef struct LNode{    int data;    //元素的信息    struct LNode *next;    //指向直接后驱的指针}LNode,*LinkList;

        从链式存储的存储结构来看,我们知道链式线性表的构建是由一个又一个结点链接而成。而说到链接,便有两种链接的方式。一种是从头插入,另一种是从尾插入。

        对于新建一个链式线性表,我们先来看一看它的尾插法

int CreatLink_L(LinkList &L,int n){    LinkList p,q;    int i;    ElemType e;    L=(LinkList)malloc(sizeof(LNode));    //带头结点的链表    if(!L) return ERROR;    //新建链表失败    L->next=NULL;    //最后一个结点的指针域为空    q=(LinkList)malloc(sizeof(LNode));    //代替头结点    q=L;    for(i=0;i<n;i++)    {        scanf("%d",&e);    //输入元素        p=(LinkList)malloc(sizeof(LNode));    //新建节点        p->data=e;            p->next=q->next;    //尾插法        q->next=p;        q=q->next;    }    return OK;}
        我们再来看一看头插法(代码差不多):

int CreatLink_L(LinkList &L,int n){LinkList p,q;int i;ElemType e;L=(LinkList)malloc(sizeof(LNode));if(!L) return ERROR;L->next=NULL;for(i=0;i<n;i++){scanf("%d",&e);p=(LinkList)malloc(sizeof(LNode));p->next=L->next;    //头插法l->next=p;}return OK;}
        我们前面说到,使用链式的线性表的一个优点就是能简化对于顺序存储来说比较复杂的插入和删除操作。我们都知道,对于链式存储来说,各数据元素之间的联系是用指针来体现的,所以我们要插入或者是删除某个结点的时候只需要改变几个指针的指向就可以了。这就是为什么链式结构在插入和删除操作方面比顺序存储更有优势的原因。

        我们先来看一看插入操作。这是在线性表的第i个位置前插入数据元素e:

int LinkInsert_L(LinkList &L,int i,ElemType e){    int j;    LinkList s,p;    p=L;j=0;    while(p&&j<i-1)    //寻找第i-1个结点    {        p=p->next;        j++;    }    if(!p||j>i-1) return ERROR;    //i小于1或者大于表长+1    s=(LinkList)malloc(sizeof(LNode));    //生成新的结点    s->data=e;s->next=p->next;    //插入表L中    p->next=s;    return OK;}
        我们再来看一看删除操作。这是在线性表中删除第I个元素,并用e返回其值:

int LinkDelete_L(LinkList &L,int i,ElemType &e){    LinkList p,q;    int j;    j=0;    p=L;    while(p->next&&j<i-1)    //寻找第i-1个结点    {        p=p->next;        j++;    }    if(!(p->next)||j>i-1) return ERROR;    //删除的位置不合理    q=p->next;    //删除结点并释放    p->next=q->next;    e=q->data;    free(q);    return OK;}

        从上面两段代码和上一篇中顺序表的插入和删除的代码比较,我们可以看出链式存储结构的插入和删除并不需要移动大量的元素,这个优点在大量数据的操作中体现得尤为明显。

        分析一下线性表的链式存储结构和顺序存储结构。我们发现因为链式存储结构采用了指针作为数据元素之间的联系,因此数据元素的插入和删除变得比较简单。但是在查找某一元素的时候,因为各数据元素之间并没有物理意义上的相连,所以必须遍历整个线性表。而对于顺序存储来说,查找就是最简单的操作~

        那么我们是不是有一种数据结构能够兼容链式存储结构和顺序存储结构各自的优势呢?在插入和删除上比较简单而在查找上面也简单,是不是真的有这种数据结构呢?我们的回答是肯定的。那就是我们待会会见到的另一种线性表的储存方式——静态链表