美文网首页程序员数据结构和算法分析
【数据结构】线性表之顺序表各种操作

【数据结构】线性表之顺序表各种操作

作者: NotFunGuy | 来源:发表于2017-07-16 20:08 被阅读257次

    网易云课堂小甲鱼课程链接:数据结构与算法

    线性表

    1.定义

    (List):由零个或多个数据元素组成的有限序列

    2.特点

    • 线性表是一个序列
    • 若元素存在多个,则第一个元素无前驱,而最后一个元素无后继,其他元素有且只有一个前驱和后继
    • 线性表强调是有限的

    3.用数学的关系标识为:

    从a1到an
    线性表中元素个数为n(n>=0),n为线性表的数据长度。若n = 0,那称为空表

    抽象数据类型

    先谈谈数据类型

    数据类型是一组性质相同的值ed集合及定义在此集合上的一些操作的总称。(官方语言很TMD难懂!)
    列如很多编程语言的整形,浮点型,字符型等就是数据类型。

    使用数据类型的目的

    由于计算机的内存有限,对数据类型进行分类,分出多种数据类型来适合不同的计算条件差异。

    高级程序语言中的数据类型

    高级程序语言(如C)中的数据类型分为两类:一类是非结构的原子类,一类是结构类型

    • 原子类型:不可以再分的基础类型,例如整形、浮点型、字符型等。
    • 结构类型:由若干个类型组合而成,是可以再分解的,例如整形数组是由若干数据组成的。

    再谈抽象

    抽象是指抽取出事物具有的普遍性的本质。抽象是一种思考问题的方式,隐藏了繁杂的具体内容。

    抽象数据类型(Abstrust Data Type,ADT)

    ADT是指一个数学模型及定义在该模型上的一组操作。(类似于C++的类)
    ADT的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关。

    描述ADT的标准格式

        ADT 抽象数据类型名称{
            数据对象(Data):<数据对象的定义>
            数据关系      :<数据关系的定义>
            基本操作(Operation):<基本操作的定义>
        }ADT抽象数据类型名称
    

    基本操作的定义格式为:

        基本操作名(参数表)
        
            初始条件:<初始条件描述>
            操作结果:<操作结果描述>
    

    基本操作有两种参数:

    • 赋值参数只为操作提供输入值
    • 引用参数以&打头,除可以提供输入值外,还将返回操作结果。

    线性表的抽象数据类型

    线性表的抽象数据类型定义:

        ADT List{
            数据对象:
            数据关系:
            基本操作:
        }ADT List
    
    线性表的基本操作有:

    线性表的存储结构和基本操作

    线性表有两种物理存储结构:顺序存储结构链式存储解构

    一、线性表的顺序存储结构(顺序表)

    定义:线性表的顺序存储结构是指用一段地址连续的存储单元依次存储线性表的数据元素


    线性表的顺序存储的结构代码:

    由于高级程序设计语言中的数组类型也有随机存取的特性,因此,通常都用数组来描述数据结构中的顺序存储结构。

    #define MAXSIZE 20  /* 定义线性表可能达到的最大长度 */
    typedef int  ElemType; /*  定义数据元素类型,类型名为ElemType,此处所定义的数据元素只包含一个int型的数据项*/
    typedef struct { /* 定义顺序表类型,类型名为SqList,包含两个数据项:数组data,用于存放数据元素,整数length表示线性表当前长度*/
        
        ElemType data[MAXSIZE];   /*定义线性表占用的数组空间*/
        int length;         /*线性表当前长度*/
        
    }SqList;
    

    注意
    1.这里封装了一个结构,事实上对数组进行封装,增加了个当前长度的变量。
    2.类型标识符ElemType可以使基本数据类型,如:intfloatchar等,也可以使struct定义的符合类型。
    3.数组下标从0开始,但元素序号从1开始。例如:顺序表的第一个元素是data[0],第i个元素是data[i-1]

    关于typedef:类型命名标识符,用于将一个类型指派给其声明符中每隔名字。
    例如:typedef int ElemType那么ElemType的类型为int
    typedef类型定义并没有引入新的类型,它只是定义了数据类型的同义词。

    顺序存储的结构封装需要的三个属性:

    • 存储空间的起始位置,数组data,它的存储位置就是线性表存储空间的存储位置。
    • 线性表的最大存储量:数组的长度MAXSIZE
    • 线性表的当前长度:length

    注意:数组的长度与线性表的当前长度需要区分一下:数组的长度是存放线性表的存储空间的总长度,一般初始化后不变。而线性表的当前长度是线性表中的元素个数,是会变化的。

    顺序存储的结构中的地址计算方法

    假设线性表的每个数据元素需要占用l个存储单元(C语言中为4个字节),并以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中的第i+1个数据元素的存储位置LOC(ai+1)和第i个数据元素的存储位置LOC(ai)之间满足的关系为:


    由此得出线性表的第i个数据元素ai的存储位置为:

    顺序表操作之获取元素操作

    • 描述:实现GetElem的具体操作,即线性表L中的第i个元素位置返回。
    • 代码:
    #define OK 1;
    #define ERROR 0;
    #define TRUE 1;
    #define FALSE 0;
    
    #define MAXSIZE 20  /* 定义线性表可能达到的最大长度 */
    typedef int  ElemType; /*  定义数据元素类型,类型名为ElemType,此处所定义的数据元素只包含一个int型的数据项*/
    typedef struct { /* 定义顺序表类型,类型名为SqList,包含两个数据项:数组data,用于存放数据元素,整数length表示线性表当前长度*/
        
        ElemType data[MAXSIZE];   /*定义线性表占用的数组空间*/
        int length;         /*线性表当前长度*/
        
    }SqList;
    
    
    typedef int Status; /*Status是函数的类型,其值是函数结果状态码,如OK等*/
    
    /**
     * 1.获取元素操作
     */
    Status GetElem(SqList L, int i, ElemType *e){
        
        if (L.length == 0 || i<1 || i>L.length) return ERROR;
        
        *e = L.data[i-1];
        
        return OK;
    }
    

    顺序表操作之插入操作

    • 描述:顺序表的插入操作是指在表中的第i(1<=i<=n+1)个位置,插入一个新元素e,使长度我n的顺序表变为长度为n+1的顺序表。
    • 插入算法思路:
      1.如果插入位置不合理,抛出异常;
      2.如果线性表长度大于等于数组长度,则抛出异常火动态增加数组容量;
      3.从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移一个位置;
      4.将要插入元素填入位置i处;
      5.线性表长度+1。
    • 代码:
    #define OK 1;
    #define ERROR 0;
    #define TRUE 1;
    #define FALSE 0;
    #define MAXSIZE 20  /* 定义线性表可能达到的最大长度 */
    typedef int  ElemType; /*  定义数据元素类型,类型名为ElemType,此处所定义的数据元素只包含一个int型的数据项*/
    typedef struct { /* 定义顺序表类型,类型名为SqList,包含两个数据项:数组data,用于存放数据元素,整数length表示线性表当前长度*/
        
        ElemType data[MAXSIZE];   /*定义线性表占用的数组空间*/
        int length;         /*线性表当前长度*/
        
    }SqList;
    
    
    typedef int Status; /*Status是函数的类型,其值是函数结果状态码,如OK等*/
    
    /**
     * 2.插入元素操作
     */
    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; //当i不在范围内时候
        
        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++; //线性表长度+1
        
        return OK;
    }
    

    顺序表操作之插入操作

    • 算法实现思路:
      1.如果删除位置不合理,抛出异常;
      2.取出删除元素;
      3.从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置。
      4.表长-1.
    • 实现代码:
    /**
     * 3.删除元素
     */
    Status ListDelete(SqList *L, int i, ElemType *e){
        
        int j;
        
        
        if (L->length == 0) return ERROR; // 线性表为空
        
        if (i<1 || i>L->length+1) return ERROR; //当i不在范围内时候
        
        *e = L->data[i-1]; // 拿到删除的元素的值
        
        if (i < L->length) {
            
            /* 将删除的元素后面的元素都向前移动一位 */
            for (j = i; j<= L->length; j++) {
                
                L->data[j-1] = L->data[j];
            }
        }
        
        L->length--;
        
        return OK;
    }
    

    线性表顺顺序存储结构的特点

    • 线性表的顺序存储结构,在存、读数据时,不管是哪个位置,时间复杂度都是O(1);
    • 在插入或删除时,时间复杂度都是O(n);
    • 这说明线性表的顺序存储结构适合元素个数比较稳定,不经常插入和删除元素,而更多的操作是存取元素的应用。

    相关文章

      网友评论

        本文标题:【数据结构】线性表之顺序表各种操作

        本文链接:https://www.haomeiwen.com/subject/wyqfhxtx.html