【数据结构--C语言】有序表算法及其应用

news2024/10/6 10:33:16

有序表是指其中的所有元素以递增或递减方式有序排列。为了简单,假设有序表以递增排列。

有序表的基本运算

  • InitLIst(&L):初始化有序表L
  • DestoryList(&L):销毁有序表L
  • ListEmpty(L):判断空表
  • ListLength(L):求有序表L的元素个数
  • DispList(L):输出表L
  • GetElem(L, i, &e):求有序表L的第i个元素
  • LocateElem(L, e):返回第一个元素为e的序号
  • ListInsert(&L, e):插入一个元素值为e的元素
  • ListDelete(&L, i, &e):删除第i个元素,并返回删除元素值

由于有序表中元素之间的逻辑关系与线性表中的完全相同,所以可以采用顺序表(SqList)和链表(单链表LinkNode、双链表DLinkNode)进行存储。

有序表的ListInsert()算法

1. 用顺序表存储有序表

// 在有序表里插入元素e
void ListInsert(SqList *&L, ElemType e) {  
    int i=0, j;

    while(i<L->length && L->data[i]<e) {  // 找到小于e的位置
        i++;
    }
    for(j=ListLength(L); j<i; j--) {  // 将data[i]及后面的元素向后移动一位
        L->data[i+1] = L->data[i];
    }
    L->data[i] = e;
    L->length++;
}

2. 用单链表存储有序表

void ListInsert(LinkNode *&L, ElemType e) {
    LinkNode *p=L, *s;
    while(p->next->data<e && p->next!=NULL) {  // 找到小于e的位置
        p = p->next;
    }
    s = (LinkNode *)malloc(sizeof(LinkNode));  // 新建一结点,将e元素存入结点s的数据域中,再将s结点插入该位置
    s->next = NULL;
    s->data = e;
    s->next = p->next;
    p->next = s;
}

有序表的归并算法

假设有两个有序表LA和LB,设计一个算法,将它们合并成一个有序表LC(假设每个有序表中和两个有序表间均不存在重复元素),要求不破坏原有表LA和LB.

思路:将两个有序表合并成一个有序表可以采用二路归并算法。

分别扫描LA和LB两个有序表,当两个有序表都没有遍历完时循环:比较LA和LB的当前元素,将其中较小的元素放入LC中,再从较小元素所在的有序表中取下一个元素。重复这一过程,直到LA或LB遍历完毕,最后将未遍历完的有序表中余下的元素放入LC中。

举例:LA=(1,3, 5),LB=(2, 4, 8, 10),以下是其二路归并过程。
请添加图片描述

1. 顺序表存放有序表时的二路归并算法

void UnionList(SqList *LA, SqList *LB, SqList *&LC) {
    int i=0, j=0, k=0;  // i, j分别是LA, LB的下标,k为LC元素的个数
    LC=(SqList *)malloc(sizeof(SqList));

    while(i<LA->length && j<LB->length) {  // 比较i和j对应的元素
        if(LA->data[i] < LB->data[j]) {
            LC->data[k] = LA->data[i];
            k++;
            i++;
        }else{
            LC->data[k] = LA->data[j];
            k++;
            j++;
        }
    }
    while(i<LA->length){  // LA没有遍历完,将其余的元素全部放入LC中
        LC->data[k] = LA->data[i];  
        k++;
        i++;
    }
    while(j<LB->length){  // LB没有遍历完,将其余的元素全部放入LC中
        LC->data[k] = LB->data[j];  
        k++;
        j++;
    }
    LC->length = k;

}

2. 单链表存放有序表时的二路归并算法

void UnionList(LinkNode *LA, LinkNode *LB, LinkNode *&LC) {
    LinkNode *pa=LA->next, *pb=LB->next, *r, *s;  
    LC = (LinkNode *)malloc(sizeof(LinkNode));
    r = LC;

    while(pa!=NULL && pb!=NULL) {
        if(pa->data < pb->data) {
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pa->data;  // 复制pa结点
            r->next = s;  // 连接到LC头结点后面
            r = s;
            pa = pa->next;
        }else{
            s = (LinkNode *)malloc(sizeof(LinkNode));
            s->data = pb->data;  // 复制pb结点
            r->next = s;  // 连接到LC头结点后面
            r = s;
            pb = pb->next;
        }
        
    }

    while(pa!=NULL) {  // LA剩余
        s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = pa->data;  // 复制pa剩下的结点
        r->next = s;  // 连接到LC头结点后面
        r = s;
        pa = pa->next;
    }
    while(pb!=NULL) {  // LB剩余
        s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = pb->data;  // 复制pb剩下的结点
        r->next = s;  // 连接到LC头结点后面
        r = s;
        pb = pb->next;
    }
    r->next = NULL; // 将LC表的尾结点的next域置空
}

两种算法的设计思路相同,我们来计算一下它们的时间复杂度。

第1个while循环在最坏情况下的执行次数为O(ListLength(LA)+ListLength(LB)),第2个while循环在最坏情况下的执行次数为O(ListLength(LA)),第3个while循环在最坏情况下的执行次数为O(ListLength(LB)),所以算法的时间复杂度为O(ListLength(LA)+ListLength(LB))。

有序表的应用

算法1:留下三个表数据值相同的结点

例题

已知3个单链表存储的有序表LA,LB,LC,元素值依次递增,使链表LA中仅留下3个表中均包含的数据元素的结点,且没有数据值相同的结点,并释放LA中其他结点。要求算法的时间复杂度为O(m+n+p),其中m,n,p分别为3个表的长度。(假设每个单链表不存在数据值相同的结点,但3个单链表中可能存在数据值相同的结点)

思路

先以单链表LA的头结点作为一个空表,r指向新建单链表的尾结点,以pa遍历单链表LA中的数据结点,判断它是否在单链表LB,LC中,若同时在,则为公共元素,将其连在r结点后面,否则删除它。

算法
void Commnode(LinkNode *&LA, LinkNode *LB, LinkNode *LC){
    LinkNode *pa=LA->next, *pb=LB->next, *pc=LC->next, *q, *r;
    LA->next = NULL;
    r = LA;  // r指向新单链表的尾结点
    
    while(pa!=NULL) {  // 查找公共结点并建立新链表LA
        while(pb!=NULL && pa->data > pb->data) {  // pa结点与LB中的pb结点比较
            pb=pb->next;
        }
        while(pc!=NULL && pa->data > pc->data) {  // pa结点与LC中的pc结点比较
            pc=pc->next;
        }
        if(pb!=NULL && pc!=NULL && pa->data == pb->data && pa->data == pc->data){ // 若pa结点是公共结点
            r->next = pa;
            r = pa;
            pa = pa->next;
        }else{  // 若pa结点不是公共结点,删除pa结点
            q = pa;
            pa = pa->next;
            free(q);
        }
    }
    r->next=NULL;
}
	

算法2:删除值域重复的结点

例题

已知一个有序单链表L(允许出现值域重复的结点),设计一个高效的算法删除值域重复的结点。

思路

有序单链表中,相同值域的结点都是相邻的。用p遍历递增单链表,所指结点的值域=后继结点值域,则删除后者。

算法
void dels(LinkNode *&L){
    LinkNode *p=L->next, *q;
    while(p->next!=NULL) {
        if(p->data==p->next->data){  // 找重复值域的结点
            q = p->next;
            p->next = q->next;
            free(q);
        }else{
            p = p->next;
        }
    }
}

该算法的时间复杂度为O(n),其中n为等长有序单链表L中数据结点的个数。

算法3:找出两个序列的中位数

例题

一个长度为n(n>1)的升序序列S,处在第n/2个位置的数称为S的中位数。现有两个等长的升序序列A和B,设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。假设升序序列采用顺序表存储。

思路

当升序序列采用顺序表存储,一个升序序列S的中位数就是S->data[S->length/2]元素。而两等长升序序列的中位数,是将它们二路归并后的一个升序序列S的中位数。实际上不需要求出S的全部元素,用k记录当前归并的元素的个数,当k=S1->length时,进行归并的那个元素就是中位数。

算法
ElemType M_Search(SqList *A, SqList *B){  // A、B长度相同
    int i=0, j=0, k=0;
    while(i<A->length && j<B->length){  // 两个序列均没有扫描完
        k++;  // 当前归并的元素个数+1
        if(A->data[i] < B->data[j]){  // 归并较小的元素 A->data[i]
            if(k==A->length){
                return A->data[i];
            }
            i++;
        }else{  // 归并较小的元素 B->data[j]
            if(k==B->length){
                return B->data[j];
            }
            j++;
        }
    }
}

该算法的时间复杂度为O(n),空间复杂度为O(1),其中n为等长有序顺序表A、B中元素的个数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1148774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql进阶-索引篇(上)

目录 索引概述 索引结构 数据结构 二叉树 红黑树 B-Tree BTree Hash 索引分类 聚集索引&二级索引 聚集索引选取规则: 具体结构 索引基础语法 SQL性能分析 SQL执行频率 慢查询日志 profile详情 explain 索引概述 介绍&#xff1a; 索引&#xff08; index &…

基于哈里斯鹰算法的无人机航迹规划-附代码

基于哈里斯鹰算法的无人机航迹规划 文章目录 基于哈里斯鹰算法的无人机航迹规划1.哈里斯鹰搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用哈里斯鹰算法来优化无人机航迹规划。 …

IOC课程整理-18 Spring注解

1. Spring 注解驱动编程发展历程 2. Spring 核心注解场景分类 3. Spring 注解编程模型 https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model 4. Spring 元注解&#xff08;Meta-Annotations&#xff09; 元注解&#xff08;Meta-A…

PostGreSQL:JSON|JSONB数据类型

JSON JSON 指的是 JavaScript 对象表示法&#xff08;JavaScript Object Notation&#xff09;JSON 是轻量级的文本数据交换格式JSON 独立于语言&#xff1a;JSON 使用 Javascript语法来描述数据对象&#xff0c;但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许…

什么是 CNN? 卷积神经网络? 怎么用 CNN 进行分类?(1)

先看卷积是啥&#xff0c;url: https://www.bilibili.com/video/BV1JX4y1K7Dr/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 下面这个式子就是卷积 看完了&#xff0c;感觉似懂非懂 下一个参考视频&#xff1a;https://www.y…

linux PELT算法中的load计算

滑窗平均的累加计算 权重y按滑窗距离衰减&#xff0c;y^32 0.5&#xff0c;也就是经历32个周期将衰减一半的权重&#xff0c;假设本周期值是&#xff36;&#xff0c;本周期的加权累加值为&#xff36;x&#xff0c;则&#xff1a; 一个完整周期是T&#xff0c;给一个基础值1…

【技能树笔记】网络篇——练习题解析(十)

【技能树笔记】网络篇系列前九篇 【技能树笔记】网络篇——练习题解析&#xff08;一&#xff09;-CSDN博客 【技能树笔记】网络篇——练习题解析&#xff08;二&#xff09;-CSDN博客 【技能树笔记】网络篇——练习题解析&#xff08;三&#xff09;-CSDN博客 【技能树笔记】网…

大数据Flink(一百零五):SQL性能调优

文章目录 SQL性能调优 一、 ​​​​​​​MiniBatch 聚合

2023 年值得关注的国外网络安全初创公司

网络安全初创公司试图解决的问题往往有点超前于主流。他们可以比大多数老牌公司更快地填补空白或新兴需求。初创公司通常可以更快地创新&#xff0c;因为它们不受安装基础的限制。 当然&#xff0c;缺点是初创公司往往缺乏资源和成熟度。公司致力于初创公司的产品或平台是有风…

JavaWeb 怎么在servlet向页面输出Html元素?

service()方法里面的方法体&#xff1a; resp.setContentType("text/html;charsetutf-8");//获得输出流PrintWriter对象PrintWriter outresp.getWriter();out.println("<html>");out.println("<head><title>a servlet</title>…

SDL事件处理以及线程使用(2)

事件使用 #include <stdio.h> #include <SDL.h>#define FF_QUIT_EVENT (SDL_USEREVENT 1) // 定义自定义事件#undef main int main() {SDL_Window* pWindow NULL;SDL_Init(SDL_INIT_VIDEO);// 创建窗口pWindow SDL_CreateWindow("Event Test Title&…

DAY38 动态规划 + 509. 斐波那契数 + 70. 爬楼梯 + 746. 使用最小花费爬楼梯

动态规划理论 动态规划&#xff0c;Dynamic Programming&#xff0c; DP&#xff0c; 如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#xff0c;贪心没有状态推导…

OpenTiny Vue 支持 Vue2.7 啦!

你好&#xff0c;我是 Kagol。 前言 上个月发布了一篇 Vue2 升级 Vue3 的文章。 &#x1f596;少年&#xff0c;该升级 Vue3 了&#xff01; 里面提到使用了 ElementUI 的 Vue2 项目&#xff0c;可以通过 TinyVue 和 gogocode 快速升级到 Vue3 项目。 有朋友评论替换butto…

校园物业报修小程序开发笔记一

背景 校园规模和复杂性&#xff1a; 大型学校和校园通常拥有众多的建筑物、设施和设备&#xff0c;需要有效的维护和报修系统&#xff0c;以满足学生、教职员工和校园管理人员的需求。 学生和员工需求&#xff1a; 学生和员工在校园内可能遇到各种维修问题&#xff0c;如故障的…

精品Python的大学教室资源预约管理系统

《[含文档PPT源码等]精品基于Python的大学教室资源管理系统的设计与实现》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前…

0028Java程序设计-智能农场监控报警系统设计与实现

文章目录 摘要目 录系统设计开发环境 摘要 我国是一个以农业为主的国家&#xff0c;在当今社会信息化迅速发展的背景下&#xff0c;将信息技术与农业相融合是必然的趋势。现代信息技术在农业生产中的运用&#xff0c;主要体现在两个领域&#xff1a;一是传感器技术&#xff1b…

基于SpringBoot和Vue的车辆违章信息查询系统

一、绪论 1.1 研究背景 当前社会交通事故频发&#xff0c;车辆违章现象屡见不鲜。为了解决这一问题&#xff0c;车辆违章信息查询系统应运而生。该系统能够自动检测车辆违章行为并提供相关信息&#xff0c;为交通管理提供了便利。 目前&#xff0c;基于 Java 语言的前后端完…

0030Java程序设计-积分管理系统论文

文章目录 摘  要**目  录**系统实现系统功能需求3.2.1 管理员功能3.2.2 柜员功能 开发环境 摘  要 随着计算机和网络的不断革新&#xff0c;世界已经进入了前所未有的电子时代。作为实用性强、应用范围广泛的会员管理系统也正在被越来越多的各类企业用于消费管理领域。然…

丰富你的场景验证用例

即使对于一个非常简单的IP&#xff0c;我们也无法验证充分&#xff0c;或者说无法证明芯片没有bug。一个验证人员所能够做的就是尽可能地发现更多的bug&#xff0c;增强流片成功的信心。 对于芯片的验证用例&#xff0c;在各个基本分支通路都已经覆盖了之后&#xff0c;还需要考…

Proteus仿真--单个数码管循环显示0-9(仿真文件+程序)

本文主要介绍基于51单片机的单个数码管循环显示0-9&#xff0c;Proteus仿真&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真运行视频 Proteus仿真--单个数码管循环显示0-9&#xff08;仿真文件程序&#xff09; 附完整Proteus仿真资料代码资料 百度网盘链接: ht…