数据结构——线性表的顺序表示和实现

线性表的顺序表示和实现

    • 顺序表的概念和特点
    • 顺序表的实现

顺序表的概念和特点

  1. 直接将线性表的逻辑结构映射到存储结构上。

  2. 基地址LOC(a1):顺序表中第一个数据元素a1的存储位置,也是线性表的起始位置。

  3. 线性表的顺序存储结构或顺序映像,称这种存储结构的线性表为顺序表。

  4. 顺序表的特点:为表中相邻的元素ai和ai+1赋以相邻的存储位置LOC(ai)和LOC(ai+1)。

  5. 以元素在计算机内“物理位置相邻”来表示线性表中的数据元素之间的逻辑关系。

  6. 每一个数据元素的存储位置都和线性表的起始位置相差一个 和数据元素在线性表中的位序成正比的常数 。

  7. 线性表的顺序存储结构是一种随机存取的存储结构。

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

  9. 因为线性表的长度可变,所需最大存储空间随问题不同而不同,所以在C语言中可用动态分配的一维数组进行描述。

顺序表的实现

  1. 线性表的动态分配顺序存储结构

    #define MAXSIZE  100   // 线性表存储空间的初始分配量
    typedef struct {
        ElemType  data[MAXSIZE];  // 存放顺序表的数组
        int length;       // 当前长度
     }SqList;
    
  2. // 初始化顺序表
    void InitList(SqList &L){
        L=(SqList *) malloc(sizeof(SqList));
        // L指的是SqList *的指针,指向名为SqList的结构体
    	// malloc(sizeof(SqList))指的是向系统内存申请大小为sizeof(SqList)的内存地址
        // (SqList *)指的是把这个地址强制转化为SqlList *的指针
     	L->length = 0;  // 将当前线性表长度置0
    }
    // 时间复杂度为O(1)
    
  3. 创建顺序表:已知数组a[n],数组中的元素依次插入到顺序表L中,从而建立顺序表。

    // 建立顺序表(插入数据)
    void CreateList(SqList *&L,ElemType  a[],int n) { // 由a中的n个数据元素
        L=(SqList *) malloc (sizeof(SqList)); // 分配存放线性表的空间
        for(int i=0; i < n; i++) { // 遍历数组元素,放置数据元素。
            L->data[i] = a[i];     // L->data[i]  顺序表L的第i个元素
        }
        L->length = n;             // 最后将顺序表L的表长设为n;
    }
    
  4. 顺序表的插入:在表中的第i个位置上插入一个值为x的新元素,插入后使得原表长为n的表变成表长为n+1的表,i的取值范围为1≤i≤n+1。

    仅当在表的最后插入(即插入位置为i=n+1)时,才无需移动结点,直接将x插入表的末尾即可。

    如果在表的中间插入元素,则需要将位置在n,n-1,……,i的结点依次往后移一个位置到n+1,n,……,i+1处。

    步骤为:

    ① 将an ~ ai按从后往前的顺序向后移动,为新元素让出第i个位置。

    ② x置入空出的第i个位置。

    ③ 修改表长。

    bool InsertList(SqList &L, int i, ElemType x) {
        int j;
        if(L->length == MAXSIZE - 1)     // 表空间已满,不能插入
            return Overflow;
        if(i < 1 || i > L->length + 1)   // 插入的位置i的值不合规时
            return Error;
    	for(j = L->length; j>=i; j--) {  // 从表中最后一个元素开始往前
            L->data[j+1] = L->data[j];   // 依次往后移动一个位置 即将第j个位置的值赋给第j+1个位置。
        }
        L->data[i] = x;   // 将需要插入的元素x的值,赋给L的第i个位置 
        L->length++;      // L的长度加1
        return TRUE;      // 插入成功
    }
    

    注:插入算法的时间复杂度分析:时间主要消耗在数据元素的移动上,有n+1个位置可以插入。

    最好的情况:如果插入的元素在线性表的最后一个位置(L的表尾),则不需要移动元素,在最后一个位置插入元素即可。时间复杂度为O(1).

    最坏的情况:如果插入的元素在线性表的第一个位置(L的表头),则需要移动n个元素,时间复杂度为O(n)

    平均时间复杂度为O(n)。

  5. 顺序表的删除:指将表中第i个元素从线性表中删除,删除后使原表长为n的线性表变为表长为n-1的线性表,i的取值范围为1≤i≤n。操作如下:

    ① 将ai+1 ~ an 从前往后依次向前移动,覆盖原来位置的数据元素

    ② 将线性表L的长度L->length减1。

    bool DeleteList(SqList &L,int i, Elemtype &e){
        if( i < 1 || i > L->length){  // 检查是否为空表以及删除的位置是否合法。
            return Error;
        }
        *e = L->data[i];  // 用*e 存储待删除的元素值,将待删除的元素放入临时空间中,
        for(j=i;j<=L->length-1;j++) {
            L->data[j] = L->data[j+1];  // 向前移动,覆盖前面的数据
        }
        L->length--;
        return Ture;
    }
    

    注:删除算法的时间复杂度分析:时间主要消耗在数据元素的移动上,移动元素的个数取决于删除元素的位置。

    最好的情况:当删除的元素位于表尾时(即i=n),无需移动元素,时间复杂度为O(1)。

    最坏的情况:当删除的元素位于表头时(即i=1),需要移动除表头之外的所有元素,时间复杂度为O(n)。

    平均时间复杂度为O(n)。

  6. 顺序表的查找:在顺序表L中查找第一个元素值等于e的元素,并返回其位序。步骤如下:

    ① 从第一个元素起,依次和e相比较,若找到与e相等的元素L->data[i],则查找成功,返回该元素的序号i+1。

    ② 若查遍整个顺序表都没有找到,则查找失败,返回0。

    int LocateElem(SqList L, Elemtype e){
        for(i=0; i<L->length;i++) {
            if(L.data[i]==e){   
                return i+1;    // 下标为i的元素值等于e,返回其位序i+1
            }
        }
        return 0;     //退出循环,说明查找失败。 
    }
    

    当在顺序表中查找一个数据元素时,其时间主要消耗在数据的比较上,而比较的次数取决于被查元素在线性表中的位置。

    最好的情况:查找的元素就在表头,仅需比较一次,时间复杂度为O(1)

    最坏的情况:查找的元素在表尾(或者不存在)时,则需要比较n次,时间复杂度为O(n)。

    顺序表按值查找算法的平均时间复杂度为O(n)。

你可能感兴趣的:(数据结构,数据结构,算法,链表)