线性表顺序存储结构

先看看官方是怎么定义线性表的吧!

线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储),但是把最后一个数据元素的尾指针指向了首位结点)。
各位看完了吧,接下来该轮到我来讲解了!
其实线性表也可以称之为序列表,因为他是有序的,
所以可以用C语言里的一维数组来实现,线性表中首元素无前驱,末元素无后继,除首尾元素外,中间的其他元素既有前驱也有后继,什么是前驱是什么后继呢?
就拿我对象的所工作的幼儿园小朋友们来举例子吧!
在课外活动中,老师让每个小朋友们手拉着旁边小朋友们的手形成一列,最靠左的小朋友们,他的右手没有人拉他,即没有前驱,靠最右边的小朋友他的左手没人拉,即无后继,而中间的小朋友们的左右手都有其他小朋友们拉着,即有前驱和后继。
并且队列中小朋友们的人数不能大于全班所有小朋友的人数,也就是所谓的队列的长短要小于整个数组的大小
那么接下来咱们实现一下小朋友们手拉手形成的线性表吧!
首先咱们得先创造小朋友们,有人说小朋友都是爹妈生的,你咋造!你可以把我比作女娲吧,~哈哈!因为小朋友们成长离不开所需的营养元素,咱们先看看需要什么营养元素吧!
#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;    /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Elemtype;  /* ElemType类型根据实际情况而定,这里假设为int 

看完了小朋友们所需的生长元素,接下来就开创造小朋友们吧!

typedef struct
{
    ElemType data[MAXSIZE]; /* 数组,存储数据元素 */
    int length;             /* 线性表当前长度 */
}SqList;

小朋友们被造好之后,咱们为了让小朋友们站的更整齐些,于是画一行正方形的位置块,让每个小朋友们手拉着手站在各自的块里,像下面这样

/* 初始化顺序线性表 */
Status InitList(SqList *L)
{
    L->length = 0;
    return OK;
}

 画完格子后,怕有些淘气的小朋友们站在格子里玩耍,咱们得先看看格子里是不是空的

Status ListEmpty(SqList L)
{
    if (L.length == 0)
    {
        return TRUE;
    }
    else{
        return FALSE;
    }
}

如果此时有小朋友们站在格子里,咱们得告诉他,让他离开,使格子里面没有小朋友

/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(SqList *L)
{
    L->length = 0;
    return OK;
}

现在有新来的小朋友加入我们,那么咱们让新来的小朋友手去她喜欢的格子里,然后开始做游戏了

Status ListInsert(SqList *L, int i, ElemType e)
{
    int k;
    if (L->length == MAXSIZE) /* 顺序线性表已经满 */
    {
        return ERROR;
    }
    if (i<1 || i>L->length+1)/* 当i比第一位置小或者比最后一位置后一位置还要大时 */
    {
        return ERROR;
    }
    if (i <= L->length)
    {
        for (k = L->length - 1; k >= i - 1; k--)
        {
            L->data[k + 1] = L->data[k];
        }
    }
    L->data[i - 1] = e;
    L->length++;
    return OK;
}

但是有的小朋友们不乖,骚扰左右的小朋友,因此,需要让他出队面壁思过去

/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L, int i, ElemType *e)
{
    int k;
    if (L->length = 0)   /* 线性表为空 */
    {
        return ERROR;
    }
    if (i<1 || i>L->length - 1) /* 删除位置不正确 */
    {
        return ERROR;
    }
    *e = L->data[i];
    if (i < L->length) /* 如果删除不是最后位置 */
    {
        for (k = i; k < L->length; k++)  /* 将删除位置后继元素前移 */
        {
            L->data[k-1] = L->data[k];
        }
    }
    L->length--;
    return OK;
}

在整个队列里面,花花小朋友表现得最好,咱们数数花花在哪个位置吧

int LocateElem(SqList L, ElemType e)
{
    int i=0;
    if (i >= L.length || L.length==0)
    {
        return 0;
    }
    for (i = 0; i < L.length; i++)
    {
        if (L.data[i] == e)
        {
            break;
        }
    }
    return i + 1;
}

咱们再来查查哪个小朋友站在第i个位置啊

Status GetElem(SqList L, int i, ElemType *e)
{
    if (i < 1 || i > L.length || L.length == 0)
    {
        return ERROR;
    }
    *e = L.data[i-1];
    return OK;
}

小朋友们表现得都很不错,咱们现在来看看一共有多少个小朋友参加这个游戏

int ListLength(SqList L)
{
    return L.length;
}

小朋友们这个游戏好不好玩啊!好玩的话,请大家记住好自己的位置,咱们下次再继续玩!

Status ListTraverse(SqList L)
{
    int i;
    for (i = 0; i < L.length; i++)
    {
        printf("%d", L.data[i]);
    }
    printf("\n");
    return OK;
}

好了,咱们开始测试一下,咱们的代码吧!

void unionL(SqList *La, SqList Lb)
{
    int La_len, Lb_len, i;
    ElemType e;
    La_len = ListLength(*La);
    Lb_len = ListLength(Lb);
    for (i = 1; i <= Lb_len; i++)
    {
        GetElem(Lb, i, &e);
        if (!LocateElem(*La, e))
            ListInsert(La, ++La_len, e);
    }
}

int main()
{
    SqList L;
    SqList Lb;

    ElemType e;
    Status i;
    int j, k;
    i = InitList(&L);
    printf("初始化L后:L.length=%d\n", L.length);
    for (j = 1; j <= 5; j++)
        i = ListInsert(&L, 1, j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L);

    printf("L.length=%d \n", L.length);
    i = ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n", i);

    i = ClearList(&L);
    printf("清空L后:L.length=%d\n", L.length);
    i = ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n", i);

    for (j = 1; j <= 10; j++)
        ListInsert(&L, j, j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L);

    printf("L.length=%d \n", L.length);

    ListInsert(&L, 1, 0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L);
    printf("L.length=%d \n", L.length);

    GetElem(L, 5, &e);
    printf("第5个元素的值为:%d\n", e);
    for (j = 3; j <= 4; j++)
    {
        k = LocateElem(L, j);
        if (k)
            printf("第%d个元素的值为%d\n", k, j);
        else
            printf("没有值为%d的元素\n", j);
    }


    k = ListLength(L); /* k为表长 */
    for (j = k + 1; j >= k; j--)
    {
        i = ListDelete(&L, j, &e); /* 删除第j个数据 */
        if (i == ERROR)
            printf("删除第%d个数据失败\n", j);
        else
            printf("删除第%d个的元素值为:%d\n", j, e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L);

    j = 5;
    ListDelete(&L, j, &e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n", j, e);

    printf("依次输出L的元素:");
    ListTraverse(L);

    //构造一个有10个数的Lb
    i = InitList(&Lb);
    for (j = 6; j <= 15; j++)
        i = ListInsert(&Lb, 1, j);

    unionL(&L, Lb);

    printf("依次输出合并了Lb的L的元素:");
    ListTraverse(L);


    getchar();
    return 0;
}

 总结:

1、首先关于表里功能函数的形参问题,有的形参被设定为 SqList *L,而有的为SqList L,这个得看需对整个列表做什么操作了,如果需要对整个列表进行初始化、插入、删除、设为空,则形参应为SqList *L,若对列表操作仅仅是查找,打印,不影响整个列表的框架操作,形参则设置为SqList L。

2、关于L->length和L.length的问题

若功能函数的形参为SqList *L,则可以进行L->length操作,若功能函数的形参为SqList L,则可以进行L.length操作。

首先L->length是对整个序列中元素的序号进行操作的,若L->length=0;则表示将序列清空 ,若L->length==n,则序列里有n个元素。

而L.length则表示的是序列最后一个元素的序号,若L.length==0,则表示序列为空表,若L.length==n,同样也表示为序列里有你个元素

 

 

 

 

posted @ 2019-05-02 15:36  追风的小蚂蚁  阅读(262)  评论(0编辑  收藏  举报