数据结构——线性表

旧城冷巷雨未停 提交于 2019-12-21 15:50:00

线性表是最简单的数据结构,其主要特征有:

1、 每个线性表只有一个头元素,一个尾元素;

2、 除第一个数据元素外,每个元素都有一个直接前驱;

3、 除最后一个数据元素外,每个元素都有一个直接后继。

 

一、 顺序表

顺序表是用数据元素在物理上的相邻表示逻辑上的相邻。顺序表具有随机存取的特性。

用动态分配的一位数组表示顺序表如下:

#define LIST_INIT_SIZE 100
#define LISTINCREMENT 50
typedef struct{
    ElemType *elem;
    int length;
    int listsize;
}SqList;

 

初始化顺序表:

Status InitList_Seq(SqList &L)
{
    L.elem = (ElemType*)malloc(LIST_NINT_SIZE*sizeof(ElemType));
    if(!L.elem)
        exit(OVERFLOW);
    L.length = 0;
    L.lisesize = LIST_INIT_SIZE;
    return OK;
}

顺序表的插入:

Status ListInsert_Seq(SqList &L, int i, ElemType e)
{
    if(i < 1 || i > L.length + 1)
        return ERROR;
    if(L.length >= L.listsize)
    {
        newbase = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));
        if(!newbase)
            exit(OVERFLOW);
        L.elem = newbase;
        L.listsize += LISTINCREMENT;
    }
    q = &(L.elem(i-1));
    for(p = &(L.elem[L.length-1]); p >= q;p--)
        *(p+1) = *p;
    *q = e;
    L.length++;
    return OK;
}

 

顺序表的删除:

Status ListDelete_Seq(SqList &L, int i, ElemType &e)
{
    if(i < 1 || i > L.length)
        return ERROR;
    p = &L.elem[i-1];
    e = *p;
    for(q = L.elem+L.length-1; p < q; p++)
        *p = *(p+1);
    L.length--;
    return OK;
}

 

 

从以上伪码可知,在顺序表中插入或删除一个元素,需要移动多个元素。对于插入,Ei  = n/2; 对于删除, Ed =  (n-1)/2。

 

二、单链表

和顺序表不同,单链表是用指针来表示数据元素之间的关系。单链表的每个结点包含两个域:一个数据域,用来存储数据元素的信息;一个指针域,用来存储后续节点的位置信息。数据元素之间的逻辑关系是用指针来表示的。逻辑上相邻的数据元素,在物理上不一定是相邻的。这样的存储结构便失去了随机存取的特性。但他的优点是插入和删除结点的时候不需要移动数据元素了。

线性表的单链表存储结构

typedef struct LNode{
    ElemType data;
    struct Lnode *next;
}LNode, *LinkList;

 

单链表中插入一个结点:

Status ListInsert_L(LinkList &L, int i, ElemType e)
{
    p = L;
    j = 0;
    while(p && j < i-1)
    {
        p = p->next;
        j++;
    }
    if(!p || j > i-1)
        return ERROR;
    s = (LinkList)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return OK;
}

 

单链表中删除一个元素结点:

Status ListDelete_L(LinkList &L, int i, ElemType &e)
{
    p = L;
    j = 0;
    while(p && j < i-1)
    {
        p = p->next;
        j++;
    }
    if(!p || j > i-1)
        return ERROR;
    q = p->next;
    e = q->data;
    p->next = q->next;
    free(q);
    return OK;
}

 

 

 

虽然单链表中插入和删除元素不需要移动元素了,但是获取第i个元素,却需要从头开始找起:

Status GetElem_L(LinkList L, int i, ElemType &e)
{
    p = L->next; 
    j = 1;
    while(p && j < i)
    {
        p = p ->next;
        j++;
    }
    if(!p || j > i)
        return ERROR;
    e = p->data;
    return OK;
}
 

在没有指针的编程语言中,我们可以用一维数组来表示线性链表——静态链表:

 

#define MAXSIZE 100
typedef struct{
    ElemType data;
    int cur;
}component, SLinkList[MAXSIZE];

 

 

三、双向链表

由于单链表中某些操作较为复杂,例如,PriorElem的执行时间为O(n),为了克服这种单向性的缺点,可以为每个结点设置两个指针域,一个指向后续结点,一个指向前驱结点,即双向链表。

typedef struct DuLNOde{
    ElemType data;
    struct DuLNode *prior;
    struct DuLNode *next;
}DuLNode, *DuLinkList;

双向链表的特性: d->next->prior = d->prior->next = d;

 

四、循环链表

循环链表是另外一种链式存储结构。其特点是表中最后一个结点的指针域又指向了头结点,使整个链表形成了一个环形。从任何一个结点出发都可以遍历表中的所有结点。有的时候,在循环链表中设立尾指针比设立头指针更方便。例如,合并两个链表的时候,如果有尾指针的话,合并操作将会非常简单。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!