线性表

线性表

是一种逻辑结构, 不特指某一具体在内存中以某种物理结构存储的线性结构

线性表是指具有相同特性数据元素的有限序列

分类

  • [顺序表]

  • [链表]

顺序表

  1. 物理结构(在内存中存储方式):

    连续存储, 且静态分配

  2. 数据域

    • 存放数据的data数组
    • 记录数据长度的length
  3. 结构定义:

    /*
    *ElemType是宏定义或者typedef指定的类型名
    *这里typedef是将这个结构体类型命名为SqList
    */
    
    #define MAX_SIZE 100
    
    typedef int ElemType; /**同 #define ElemType int */
    typedef struct{
       ElemType data[MAX_SIZE]; //data数组
       int length;          //顺序表长度
    }SqList;//Sequence List
    /**可以使用typedef或#define修改SqList的存储数据类型, 代码重用性强**/
  4. 关于#definetypedef

    #define 只是简单的文本替换 , 除了简写基本类型名(或者已经定义类型名)外还可以用来定义常量

    typedef 是对一个类型名起一个别名(原类型名依然可用), 可以对结构体这种复杂类型重命名

  5. 顺序表的存储范围[0, MAX_SIZE - 1] (参照数组的范围), MAX_SIZE即为最大的长度

  6. 常用操作

    • 插入: 在指定位置插入指定的数据元素

      指定位置要满足当前length 确定的范围

      eg : 若当前顺序表长度为5, 则顺序表中有效数据的存储下标范围为[0, 4](本例从0开始)

      则插入元素的位置范围为[0, 5](数组中仅有5个有效元素, 插入位置不能>=7(下标为6))

      /*
      *插入操作
      *@param: l : 顺序表
      *@param: pos : 指定插入位置
      *@param: x : 指定插入数据
      *@return : int(1 : 插入成功, 0 : 插入失败)
      */
      
      int Insert(SqList &l, int pos, ElemType x){
       if(l.length == MAX_SIZE) return 0;//数组已满,插入失败
       if(pos < 0 || pos > l.length) return 0;//指定插入位置超出范围
       for(int i = l.length - 1; i >= pos; --i)
           l.data[i + 1] = l.data[i];
       l.data[pos] = x;
       ++(l.length);    
       return 1;
      }

    • 删除: 删除指定位置的元素(可返回该元素值)

      指定位置要满足条件(不能删除不存在位置的元素)

      范围为[0, length - 1]

      /*
      *删除操作
      *@param: l : 顺序表
      *@param: pos : 指定删除位置
      *@param: x : 获取删除的元素值(删除成功时)
      *@return : int(1 : 删除成功, 0 : 删除失败)
      */
      
      int Delete(SqList &l, int pos, ElemType &x){
       if(pos < 0 || pos >= l.length) return 0;//指定删除位置超出范围
       x = l.data[pos];
       for(int i = pos; i < l.length - 1; ++i)
           l.data[i] = l.data[i + 1];
       --(l.length);    
       return 1;
      }

    • 查询: 获取指定位置的元素

      由于顺序表中存放元素的事数组, 可以依据存储位置(数组下标)随机访问

      查询时间复杂度O(1)

      ps : 自然指定位置要满足length的范围

      /*
      *查询操作
      *@param: l : 顺序表
      *@param: pos : 指定查询位置
      *@param: x : 获取查询的元素值(查询成功时)
      *@return : int(1 : 查询成功, 0 : 查询失败)
      */
      int GetElem(SqList l, int pos, ElemType &x){
       if(pos < 0 || pos >= l.length) return 0;//超范围
       x = l.data[pos];
       return 1;
      }

    • 打印: 遍历输出顺序表的元素

      void Print(SqList l){
       int len = l.length;
       if(len == 0) return;//线性表为空
       for(int i = 0; i < len; ++i)
           printf("%d%c", l.data[i], i == len - 1 ? '\n' : ' ');
      }
    • 获取长度

      int ListLength(SqList l){
       return l.length;
      }
    • 初始化:顺序表数组长度赋0值

      ​ 此时顺序表数组中或许有数据存在, 但不是有效数据,有效数据在[0, length)范围内

      void InitList(SqList &l){
       l.length = 0;
      } 
    • 按值查询:查询指定元素在顺序表数组中的位置,若不含该元素返回-1

      int LocateElem(SqList l, ElemType x){
       for(int i = 0; i < l.length; ++i)
           if(l.data[i] == x) return ;
       return -1;
      }
  7. 特点:

    • 存储密度大(无指针域)
    • 支持随机访问(下标O(1)查找)和顺序访问
    • 插入和删除操作时间复杂度为O(n),要移动元素
    • 静态分配空间, 存储空间固定
  8. 顺序表有序化:

    线性表本身是无序的(有序是指元素之间按照某种既定规则排列), 可以通过一定的插入规则使其有序

    eg : 顺序表递增插入

    int GetInsertPos(SqList l, ElemType x){
       for(int i = 0; i < l.length; ++i)
           if(l.data[i] > x) return i;
       return l.length;
    }
    
    int IncreseInsert(SqList &l, ElemType x){
       int pos = GetInsertPos(l, x);
       return Insert(l, pos, x);
    }
  9. 代码整合(CodeUp1323)

    
    #include <stdio.h>
    
    /**
    *CodeUp 1323
    *Sequence List
    **/
    
    #define MAX_SIZE 210
    
    
    #define ElemType int
    
    
    #define Status int
    
    
    #define OK 1
    
    
    #define ERROR 0
    
    //宏定义
    typedef struct{
       ElemType data[MAX_SIZE];
       int length;
    }SqList;
    
    int LocateElem(SqList l, ElemType x){
       for(int i = 0; i < l.length; ++i)
           if(l.data[i] == x) return i;
       return -1;
    }
    
    int ListLength(SqList l){
       return l.length;
    }
    
    void InitList(SqList &l){
       l.length = 0;
    }
    
    Status GetElem(SqList l, int pos, ElemType &e){
       if(pos < 0 || pos >= l.length) return ERROR;
       e = l.data[pos];
       return OK;
    }
    
    Status Insert(SqList &l, int pos, ElemType x){
       int len = ListLength(l);
       if(pos < 0 || pos > len || len == MAX_SIZE)
           return ERROR;
       for(int i = len - 1; i >= pos; --i)
           l.data[i + 1] = l.data[i];
       l.data[pos] = x;
       ++(l.length);
       return OK;
    }
    
    Status Delete(SqList &l, int pos, ElemType &e){
       if(pos < 0 || pos >= l.length) return ERROR;
       e = l.data[pos];
       for(int i = pos; i < l.length - 1; ++i)
           l.data[i] = l.data[i + 1];
       --(l.length);
       return OK;
    }
    
    void Print(SqList l){
       int len = ListLength(l);
       for(int i = 0; i < len; ++i)
           printf("%d%c", l.data[i], i == len - 1 ? '\n' : ' ');
    }
    
    void Union(SqList &la, SqList lb){
       int len_la = ListLength(la);
       int len_lb = ListLength(lb);
       for(int i = 0; i < len_lb; ++i){
           if(LocateElem(la, lb.data[i]) == -1)
               Insert(la, len_la++, lb.data[i]);
           Print(la);
       }
    }
    
    SqList la, lb;
    
    int main(){
    
       int m, n;
       int v;
    
       while(scanf("%d", &m) != EOF){
           InitList(la);
           InitList(lb);
           for(int i = 0; i < m; ++i){
               scanf("%d", &v);
               Insert(la, i, v);
           }
           scanf("%d", &n);
           for(int i = 0; i < n; ++i){
               scanf("%d", &v);
               Insert(lb, i, v);
           }
           Print(la);
           Print(lb);
           Union(la, lb);
           printf("\n");
       }
    
       return 0;
    }
    

链表

  1. 物理结构

    • 链式存储,非连续
    • 每个元素以结点形式存在
    • 结点包含指针域和数据域
      • 数据域: 存储数据
      • 指针域: 前驱(后继)结点的地址
    • 包含一个头结点,作为链表的首部
  2. 形式:

    • 单链表
    • 双向链表
    • 循环链表
    • 循环双链表
    • 静态链表
  3. 单链表

    • 结构定义

      typedef struct Node{
       ElemType data;
       Node * next;
      }LNode;
      //头结点不存储信息
    • 新建结点

      LNode * NewNode(ElemType x){
       LNode * res = (LNode *)malloc(sizeof(LNode));
       res->data = x;
       res->next = NULL;
       return res;
      }

    • 插入操作:

      • 头插法
      void InsertHead(LNode * head, LNode *tmp){
         tmp->next = head->next;
         head->next = tmp;
      }
      • 尾插法
      void InsertTail(LNode * head, LNode * tmp){
         LNode * cur = head;
         while(cur->next) cur = cur->next;
         cur->next = tmp;
      }
    • 两递增有序单链表的归并

      void Merge1(LNode * A, LNode * B, LNode * &C){
       C = A;
       LNode * p = A->next;
       LNode * q = B->next;
       free(B);
       LNode * r = C;
       while(p != NULL && q != NULL){
           if(p->data <= q->data){
               r->next = p;
               r = r->next;
               p = p->next;
           }else{
               r->next = q;
               r = r->next;
               q = q->next;
           }
       }
       if(p != NULL) r->next = p;
       if(q != NULL) r->next = q;
      }
    • 两递增有序单链表归并成递减

      void Merge2(LNode * A, LNode * B, LNode * &C){
       C = A;
       LNode * p = A->next;
       LNode * q = B->next;
       free(B);
       LNode * r;
       while(p != NULL && q != NULL){
           if(p->data <= q->data){
               r = p;
               p = p->next;
           }else{
               r = q;
               q = q->next;
           }
           InsertHead(C, r);
       }
       while(p != NULL) {
           r = p;
           p = p->next;
           InsertHead(C, r);
       }
       while(q != NULL) {
           r = q;
           q = q->next;
           InsertHead(C, r);
       }
      }
  4. 整合(CodeUp1324):

    
    #include <stdio.h>
    
    
    #include <stdlib.h>
    
    
    #define ElemType int
    
    typedef struct Node{
       ElemType data;
       Node * next;
    }LNode;
    
    LNode * NewNode(ElemType x){
       LNode * res = (LNode *)malloc(sizeof(LNode));
       res->data = x;
       res->next = NULL;
       return res;
    }
    
    void InsertHead(LNode * head, LNode *tmp){
       tmp->next = head->next;
       head->next = tmp;
    }
    
    void InsertTail(LNode * head, LNode * tmp){
       LNode * cur = head;
       while(cur->next) cur = cur->next;
       cur->next = tmp;
    }
    
    void Merge1(LNode * A, LNode * B, LNode * &C){
       C = A;
       LNode * p = A->next;
       LNode * q = B->next;
       free(B);
       LNode * r = C;
       while(p != NULL && q != NULL){
           if(p->data <= q->data){
               r->next = p;
               r = r->next;
               p = p->next;
           }else{
               r->next = q;
               r = r->next;
               q = q->next;
           }
       }
       if(p != NULL) r->next = p;
       if(q != NULL) r->next = q;
    }
    
    void Merge2(LNode * A, LNode * B, LNode * &C){
       C = A;
       LNode * p = A->next;
       LNode * q = B->next;
       free(B);
       LNode * r;
       while(p != NULL && q != NULL){
           if(p->data <= q->data){
               r = p;
               p = p->next;
           }else{
               r = q;
               q = q->next;
           }
           InsertHead(C, r);
       }
       while(p != NULL) {
           r = p;
           p = p->next;
           InsertHead(C, r);
       }
       while(q != NULL) {
           r = q;
           q = q->next;
           InsertHead(C, r);
       }
    }
    
    void Print(LNode * head){
       LNode * cur = head->next;
       printf("%d", cur->data);
       cur = cur->next;
       while(cur != NULL){
           printf(" %d", cur->data);
           cur = cur->next;
       }
       printf("\n");
    }
    
    int main(){
    
       int m, n;
       int v;
       while(scanf("%d", &m) != EOF){
           LNode * A = NewNode(-1);
           LNode * B = NewNode(-1);
           LNode * C;
           for(int i = 0; i < m; ++i){
               scanf("%d", &v);
               InsertTail(A, NewNode(v));
           }
           scanf("%d", &n);
           for(int i = 0; i < n; ++i){
               scanf("%d", &v);
               InsertTail(B, NewNode(v));
           }
           Merge1(A, B, C);
           Print(C);
       }
    
       return 0;
    }
    

  5. 特点

    • 插入删除不需要移动元素, 修改指针域,free即可
    • 动态分配
    • 只能顺序访问, 不能随机访问
    • 存储密度<1(指针域)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值