zoukankan      html  css  js  c++  java
  • 数据结构(一)线性表顺序存储实现

    (一)线性表的抽象数据类型定义

    定义:由零个(空表)或多个数据元素组成的序列
    ADT: 
        线性表List
    Data:
        线性表的数据对象集合为{a1,a2,...,an},每个元素类型为DataType。除了第一个无前驱,最后一个无后继,
        其他每个元素都有一个字节前驱和直接后继结点。数据元素间关系一对一。
    Operation:
        InitList(*L);//初始线性表,创建空表
        ClearList(*L);//清空线性表数据
        ListEmpty(L);//判断列表是否为空
        ListLength(L);//获取线性表的长度
        GetElem(L,i,* e);//获取指定位置的元素,返回在指针元素中
        LocateElem(L,e);//查找元素在线性表中的位置
        ListInsert(*L,i,e);//向线性表中指定位置插入元素
        ListDelete(*L, i, *e);//删除指定位置处的元素

    (二)线性表的实现

    #include <stdio.h>
    #include <stdlib.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);
    Status ClearList(SqList* L);
    Status ListEmpty(SqList L);
    int ListLength(SqList L);
    
    //四个元素操作,插入,删除,两种查找
    Status GetElem(SqList L,int i,ElemType* e);
    int LocateElem(SqList L, ElemType e);
    Status ListInsert(SqList* L, int i, ElemType e);
    Status ListDelete(SqList* L, int i, ElemType* e);
    
    
    void PrintList(SqList L);
    
    /*
    复习注意:
    我们要进行初始,增加,删除,是需要在原来线性表中进行,所以需要用到引用对原数据进行操作,
    而对于查找,获取长度,不需要对原来数据进行操作,我们直接对赋值后的局部变量(含有原线性表的所有数据)参数进行操作,即可
    */
    
    //四个基本操作,初始,清空,判断是否为空,获取长度
    //初始线性表
    Status InitList(SqList* L)
    {
        L->length = 0;
    
        for (int i = 0; i < MAXSIZE; i++)
        {
            L->data[i] = 0;
        }
    
        return OK;
    }
    
    //清空线性表数据
    Status ClearList(SqList* L)
    {
        L->length = 0;
        for (int i = 0; i < MAXSIZE; i++)
            L->data[i] = 0;
    
        return OK;
    }
    
    //判断列表是否为空
    Status ListEmpty(SqList L)
    {
        if (L.length == 0)
            return TRUE;
        return FALSE;
    }
    
    //获取线性表的长度
    int ListLength(SqList L)
    {
        return L.length;
    }
    
    //四个元素操作,插入,删除,两种查找
    //获取指定位置的元素,返回在指针元素中
    Status GetElem(SqList L, int i, ElemType* e)
    {
        if (L.length == 0 || i<1 || L.length < i)
            return ERROR;
        *e = L.data[i - 1];
        return OK;
    }
    
    //查找元素在线性表中的位置
    int LocateElem(SqList L, ElemType e)
    {
        int i = 0;
    
        if (L.length == 0)
            return 0;
    
        for (; i < MAXSIZE;i++)
            if (L.data[i] == e)
                break;
        if (i >= MAXSIZE)
            return 0;
    
        return i+1;    //注意线性表中的位置不是按照数组一样从0开始,而是按照我们正常习惯1开始的
    }
    
    //向线性表中指定位置插入元素
    Status ListInsert(SqList* L, int i, ElemType e)
    {
        int k;
        if (L->length == MAXSIZE)//线性表满
            return ERROR;
        if (i<1 || i>L->length+1)
            return ERROR;
        //开始进行插入操作,先判断元素插入位置,在将后面元素向后移动一位,进行插入
        if (i <= L->length)
        {
            for (k = L->length; k >= i;k--)    //只考虑插入到i=1(数组0),会简单点
                L->data[k] = L->data[k - 1];
        }
        L->data[i - 1] = e;
        L->length++;
        return OK;
    }
    
    //删除指定位置处的元素 Status ListDelete(SqList
    * L, int i, ElemType* e) { int k; if (L->length == 0 || i < 1 || i > L->length) return ERROR; //删除元素,是将后面元素前移,再将最后的元素删除 *e = L->data[i - 1]; if (i < L->length) { for (k = i; k < L->length; k++) L->data[k - 1] = L->data[k]; } L->data[L->length-1] = 0; L->length--; return OK; } //打印链表数据 void PrintList(SqList L) { printf("print list begin... "); for (int i = 0; i < L.length; i++) { printf("%d ", L.data[i]); } printf(" print list end... "); } int main() { SqList L; ElemType e; printf("1.InitList "); InitList(&L); printf("2.1 ListInsert 1-10 "); for (int i = 1; i <= 10; i++) ListInsert(&L, i, i*i + 1); printf("2.2 ListInsert 5 "); ListInsert(&L, 5, 256); printf("2.3 ListInsert 19 Error "); if (ListInsert(&L, 19, 99) == ERROR) printf("ListInsert(&L, 19, 99) Error:Out of range"); PrintList(L); printf("3.ListDelete the first:"); ListDelete(&L, 1, &e); printf("%d ", e); printf("4.ListDelete the end:"); ListDelete(&L, ListLength(L), &e); printf("%d ", e); PrintList(L); printf("5.1 find element use GetElem by index(6): "); GetElem(L, 6, &e); printf("%d ", e); printf("5.1 find element:256 index by LocateElem:"); printf("%d ", LocateElem(L, 256)); printf("6.Get List length:%d ", ListLength(L)); printf("7.ClearList "); ClearList(&L); if (ListEmpty(L)==OK) printf("8.ListEmpty "); system("pause"); return 0; }
    1.InitList
    initial List....
    2.1 ListInsert 1-10
    2.2 ListInsert 5
    2.3 ListInsert 19 Error
    ListInsert(&L, 19, 99) Error:Out of rangeprint list begin...
    2 5 10 17 256 26 37 50 65 82 101
    print list end...
    3.ListDelete the first:2
    4.ListDelete the end:101
    print list begin...
    5 10 17 256 26 37 50 65 82
    print list end...
    5.1 find element use GetElem by index(6): 37
    5.1 find element:256 index by LocateElem:4
    6.Get List length:9
    7.ClearList
    8.ListEmpty
    请按任意键继续. . .
    输出结果

    注意点:

    我们进行操作线性表是从1开始的,而数组索引是从0开始的,这是我们需要注意的地方

    (三)实现两个线性表的并集

    //实现两个线性表的并集
    void unionL(SqList* La, SqList Lb)
    {
        ElemType e;
        int i = 0;
        int La_length = ListLength(*La);
        int Lb_length = ListLength(Lb);
        for (i = 1; i <= Lb_length; i++)
        {
            GetElem(Lb, i, &e);
            if (!LocateElem(*La, e))
                ListInsert(La, La_length++, e);
        }
    }
    int main()
    {
        SqList La,Lb;
        InitList(&La);
        InitList(&Lb);
        for (int i = 1; i <= 10; i++)
        {
            ListInsert(&La, i, 3 * i);
            ListInsert(&Lb, i, 2 * i);
        }
    
        unionL(&La, Lb);
    
        PrintList(La);
    
        system("pause");
        return 0;
    }
    print list begin...
    3 6 9 12 15 18 21 24 27 2 4 8 10 14 16 20 30
    print list end...
    请按任意键继续. . .
    输出结果

     (四)地址计算方法(查找操作)时间复杂度

    假设ElemType类型数据占用C个字节存储单元,那每个元素相隔C个字节Loc(ai+1)=Loc(ai)+C
    地址计算方法Loc(ai)=Loc(a1)+(i-1)*C -->  获取存储位置的时间性能为O(1)

     (五)插入,删除操作时间复杂度

    若是在表尾部直接插入或者删除<应用时存取数据>,则此时的时间复杂度为O(1),是最好的情况,
    若是在表头进行插入或者删除,此时是最坏的情况,意味着需要移动所有的元素向前或者向后,这时的事件复杂度是O(n),
    否则若是在中间进行插入删除,位置为i,需要对元素进行遍历,将元素进行后移或者前移n-i,此时的平均移动次数和最中间元素移动相同,为(n-1)/2,平均时间复杂度还是O(n)

    (六)总结

    线性表的顺序存储结构,
    在存(是默认放在最后位置)或读取数据时,时间复杂度都是O(1)
    在插入或者删除时时间复杂度都是O(n).
    所以他比较适合于元素个数不太变化,而更多是存取数据的应用。

     (七)优缺点

    优点

    1.无须为表示表中元素之间的逻辑关系而增加额外的存储空间。
    2.可以快速的存取表中的任意位置的元素。

    缺点

    1.插入和删除操作需要移动大量的元素
    2.当线性表长度变化较大时,难以确定存储空间的容量
    3.任意造成存储空间的碎片
  • 相关阅读:
    概率面试题
    机器学习概率题总结(转载)
    筛素数以及判断数是否是素数
    腾讯2019正式批春笔试题
    推荐系统架构
    文本表示与匹配
    CTR预估经典模型总结
    spark运行原理
    leetcode 字符串动态规划总结
    无向图的邻接矩阵创建代码以及深度遍历广度遍历
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9415027.html
Copyright © 2011-2022 走看看