顺序标的创建及其基本算法

线性表的复习

提出问题

  1. 掌握线性表的逻辑结构存储结构
  2. 掌握线性表在顺序结构和链式结构上实现基本操作的方法;
  3. 理解线性表两种存储结构的不同特点及其适用场合,会针对需求选用合适的存储结构解决实际问题;
  4. 了解一元多项式的表示方法和基本运算的实现方法。

问题展开讨论

问题一: 掌握线性表的逻辑结构和存储结构

1.首先解释什么是逻辑结构?

逻辑结构描述的是 结构定义中的“关系”描述的是数据元素之间的逻辑关系,又被称为数据的逻辑结构

2.次要解释什么是存储结构

所谓的存储结构就是指 计算机中的表示形式 称为物理结构,又叫做存储结构

3.线性表的逻辑结构

描述逻辑结构 即数据元素之间存在的关系: 线性表中的元素必须有相同的特性 而且有且仅有一个直接前驱 和 直接后继

4.线性表的存储结构

线性标的存储结构分为两种,其中第一种为顺序存储,第二种为链式存储

问题二:掌握线性表在顺序结构和链式结构上实现基本操作的方法

本篇主要讲解顺序结构的实现和操作方法

线性表的线顺序存储表示指的是用一组地址连续的存储单元依次存储线性表对的数据元素

特点:为表中相邻的的元素ai和ai+1赋以相邻的存储位置LOC(ai)和LOC(ai+1),就是计算机内存内存地址是连续的

定义补充

#define OK 1			// 成功返回OK -> 1
#define ERROR 0			// 错误返回ERROR -> 0
#define TRUE 1			// 布尔值 true -> 1
#define FLASE 0			// 布尔值 flase -> 0
#define INFEASIBLE -1	// 不可行返回 INFEASIBLE -> -1
#define OVERFLOW -2		// 分配空间失败 内存不足 OVERFLOW -> -2
typedef int Status;		// 定义返回状态
typedef int ElemType;	// 定义数据类型为int
// -----线性表的动态分配顺序存储结构----
#define LIST_INIT_SIZE 100  // 初始分配空间大小
#define LISTINCREASEMENT 10 // 存储空间增加量
typedef struct {
    ElemType *elem;    		// 存储线性表的基址(顺序表的首地址)
    int length;				// 当前顺序表的长度
    int size;				// 当前分配的存储容量
}SqList;
  1. 初始化顺序表

    Status InitList_Sq(sqList* L){
        // 构造一个空的线性表L
        L->elem = (ElemType*)malloc(sizeof(ElemType)*LIST_INIT_SIZE);
        // 存储表分配失败 返回错误码OVREFLOW 退出程序
        if (!L->elem) exit(OVERFLOW);
        // 空表长度为0
        L->length = 0;
        // 标的当前容量
        L->listsize = LIST_INIT_SIZE;
        return OK;
    }
    
  2. 顺序表的插入操作

    线性表的插入操作是向ai和ai+1中间插入一个新的数据元素,使原长度为

    的线性表变成长度为n+1的线性表

    由于逻辑上相邻的顺序表在物理位置上也是相邻的所以必须要从ai开始向后移动n-i+1元素

    如果想不明白为什么是n-i+1元素不妨举个例子试一试

    一共有6个数字 在第一个和第二个元素之间插入一个数字 就是要移动6-2+1=5个元素 不是吗?

    初始条件:

    • 线性表L存在
    • 1 <= i <= L.length

    操作结果:

    • 在L中第i个位置之前插入一个元素e,L的长度增加1
    Status ListInsert_Sq(sqList *L, int i, ElemType e){
        // 注:此处给出的i的位置 是从1开始的 不是从0开始的 是逻辑上的
        // i 的合法值为 1 - length+1 ,其他均为非法,非法时返回ERROT
        if (i < 1 || i > L->length + 1) return ERROR;
        // 判断当前存储空间是否已满,满了以后增加分配内存(如果当前长度大于等于存储空间即内存已满)
        if (L->length >= L->listsize){
            ElemType *newbase = NULL;
            // 分配新的内存
            newbase = (ElemType *)realloc(L->elem, (L->listsize + LISTINCREASEMENT)*sizeof(ElemType));
            // 存储分配失败 退出 返回退出码
            if (!newbase) exit(OVERFLOW);
            // 新的基址
            L->elem = newbase;
            // 增加存储容量
            L->listsize = L->listsize+LISTINCREASEMENT;
        }
        // q为插入的位置
        ElemType* q = &(L->elem[i-1]);
        ElemType* p = NULL;
        // 从最后的位置开始依次向后移动一个元素
        for (p = L->elem[L->length-1]; p >= q; --p) *(p+1) = *p;
        // 为插入位置赋值
        *q = e;
        // 长度+1
        ++L->length;
        return OK;
    }
    
  3. 顺序表的删除操作

线性表的删除操作是将ai删除,使原长度为n的线性表变成长度为n-1的线性表

删除第i个元素时需要将从第i+1至第n个元素依次向前移动一个位置(把前一个元素挨个覆盖)

需要移动n-i个元素 不明白? 举个例子

一共有6个数字 删除第2个元素 要移动6-3+1=4个元素 让我们进行广义化就是n-(i+1)+1=n-i个元素 对吧!

初始条件:

  • 线性表L存在
  • 1 <= i <= L.length

操作结果:

  • 在L中将第i个位置元素删除,L的长度减一,并将删除的元素保存

删除本质:

  • 删除操作的本质就是对删除位置的元素进行覆盖,从删除元素的下一个位置对前一个元素进行覆盖操作

    最终是顺序表的长度减1就可以了

Status ListDelete_Sq(sqList *L, int i, ElemType* e){
    // 如果给出的位置不合法贼返回错误代码
    if (i < 1 || i > L->length + 1) return ERROR;
    // 创建一个指向想要删除元素的位置
    ElemType* p = &(L->elem[i-1]);
    // 创建一个空指针 用来接收元素
    ElemType* q = NULL;
    // 将要删除的元素传递出去
    e = *p;
    // 从将要删除的元素开始对前一个元素进行覆盖
    for (q = &(L->elem[L->length-1]), ++p; p <= q; ++p) *(p-1) = *p; 
    // 长度减1
    --L->length;
    return OK; 
}
  1. 顺序表中的查找操作

初始条件:

  • 线性表L存在
  • 比较函数存在
  • 需要查找的元素存在

操作结果:

  • 查找元素e如果存在返回在顺序表中的位置,否则返回0
 int LocateElem_Sq(sqList L, ElemType e, Status (* compare)(ElemType, ElemType)){
     // 设定i为存储元素的位置
     int i = 1;
     // 将顺序标的首地址赋给指针p
     ElemType* p = L.elem;
     // 如果i的位置小于等于顺序标的长度并且进行比较且不相等,继续查找下一个位置 i始终记录的当前查找元素的位置
     while (i <= L.length && !(*compare)(e, *p++)) i++;
     // 如果i的长度小于等于顺序标的长度等于查找到了元素 返回其位置
     if (i <= L.length) return i;
     // 没有查找到元素的位置 返回0
     return 0;
 }
  1. 比较两个元素是否相等

初始条件:

  • 两个需要比较的元素

操作结果:

  • 如果相等返回TRUE 否则返回FALSE
// 该函数比较简单不过多解释
Status compare(ElemType e1,ElemType e2){
     if (e1 == e2) return TRUE;
     else return FALSE;
}
  1. 合并两个顺序表

初始条件:

  • 存在两个有序的顺序表 按照非递减的顺序排列

操作结果:

  • 返回一个合并过后的非递减序列
  void MergeList_Sq(sqList La, sqList Lb, sqList* Lc){
     ElemType* pa = La.elem; 
     ElemType* pb = Lb.elem; 
     Lc->listsize = pa->length + pa->length;
      // 分配空间
     ElemType* pc = Lc->elem = (ElemType*)malloc(sizeof(ElemType)*Lc->listsize); 
      // 分配失败 退出程序
     if (!pc->elem) exit(OVERFLOW); 
     ElemType* pa_last = La.elem + La.length - 1; 
     ElemType* pb_last = Lb.elem + Lb.length - 1;
      // 对两个顺序表进行归并 
     while (pa <= pa_last && pb <= pb_last) {
        if (*pa <= *pb) *pc++ = *pa++; 
        else *pc++ = *pb++; 
     }
     // 将顺序表pa中剩余的元素插入
     while(pa <= pa_last) *pc++ = *pa++;
      // 将顺序表pb中剩余的元素插入
     while(pb <= pb_lbst) *pc++ = *pb++; 
     Lc->length = Lc->listsize; 
}

转载自WsW的博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值