数据结构 排序
目录
- 第八章 排序
- 8.1排序的基本概念
- 1. 概念
- 2. 排序算法的分类
- 8.2 插入排序
- 8.2.1 直接插入排序
- 8.2.2 算法效率分析
- 8.2.2 折半插入排序
- 总结
- 8.2.3 希尔排序
- 8.3 交换排序
- 8.3.1冒泡排序
- 8.3.2快速排序(了解栈的过程)
- 8.4 选择排序
- 8.4.1 简单选择排序
- 8.4.2 堆排序
- 8.4.3 堆的插入删除
- 8.5 归并排序(Merge Sort)内外部排序
- 8.6 基数排序(Radix Sort)
- 排序方式
- 递减
- 递增
- 算法效率分析
- 基数排序的应用
- 各种内部排序算法的比较及应用
- 内部排序算法的应用
- 8.7 外部排序
- 8.7.1 归并排序的实现
- 内存、外存之间的数据交换
- 外部排序原理
- 时间开销分析
- 优化
- 多路归并
- 减少初始归并段数量
- 什么是多路平衡归并?
- 8.7.2 败者树
- 败者树的构造
- 败者树的使用
- 败者树在多路平衡归并中的应用
- 败者树的实现思路
- 8.7.3 置换-选择排序
- 8.7.4 最佳归并树
- 归并树的性质
- 构造2路归并的最佳归并树
- 多路归并的情况
- 添加虚段的数量
- 数据结构结束
第八章 排序
8.1排序的基本概念
1. 概念

- 排序:重新排列表中的元素,使表中元素满足按关键字有序的过程(关键字可以相同)
- 排序算法的评价指标:时间复杂度、空间复杂度;
- 排序算法的稳定性:关键字相同的元素在排序之后相对位置不变,称为稳定的;(选择题考查)
Q: 稳定的排序算法一定比不稳定的好?
A: 不一定,要看实际需求;
2. 排序算法的分类

- 内部排序: 数据都在内存——关注如何使时间、空间复杂度更低;
- 外部排序: 数据太多,无法全部放入内存——关注如何使时间、空间复杂度更低,如何使读/写磁盘次数更少;
之所以有这种分类是因为磁盘的容量一般远大于内存,而运算速度又远不如内存。因此排序算法不仅要关注时间和空间复杂度,有时考虑到内存容量的问题还要关注如何使读/写磁盘次数更少
8.2 插入排序
8.2.1 直接插入排序
-
算法思想: 每次将一个待排序的记录按其关键字大小,插入(依次对比、移动)到前面已经排好序的子序列中,直到全部记录插入完成
-
代码实现:

不带“哨兵”
void InsertSort(int A[], int n){ //A中共n个数据元素int i,j,temp;for(i=1; i<n; i++)if(A[i]<A[i-1]){ //A[i]关键字小于前驱temp = A[i]; for(j=i-1; j>=0 && A[j]>temp; --j)A[j+1] = A[j]; //所有大于temp的元素都向后挪A[j+1] = temp; //复制到插入位置}
}
带“哨兵” ,优点:不用每轮循环都判断j>=0

void InsertSort(int A[], int n){ //A中从1开始存储,0放哨兵int i,j;for(i=1; i<n; i++)if(A[i]<A[i-1]){ A[0] = A[i]; //复制为哨兵for(j=i-1; A[0] < A[j]; --j) //从后往前查找待插入位置A[j+1] = A[j]; //向后挪动A[j+1] = A[0]; //复制到插入位置}
}
8.2.2 算法效率分析
-
空间复杂度:O(1)
-
时间复杂度:主要来自于对比关键字、移动关键字,若有n个元素,则需要n-1次处理
-
最好情况: 原本为有序,共n-1趟处理,每一趟都只需要对比1次关键字,不需要移动元素,共对比n-1次 —— O(n)
-
最差情况: 原本为逆序 —— O(n²)
-
平均情况:O(n²)
-
算法稳定性:稳定
8.2.2 折半插入排序
思路: 先用折半查找找到应该插入的位置,再移动元素;
-
为了保证稳定性,当查找到和插入元素关键字一样的元素时,应该继续在这个元素的右半部分继续查找以确认位置; 即当 A[mid] == A[0] 时,应继续在mid所指位置右边寻找插入位置
-
当low>high时,折半查找停止,应将[low,i-1]or[high+1,i-1]内的元素全部右移,并将A[0]复制到low所指的位置;
代码实现
void InsertSort(int A[], int n){ int i,j,low,high,mid;for(i=2;i<=n;i++){A[0] = A[i]; //将A[i]暂存到A[0]low = 1; high = i-1; //折半查找的范围while(low<=high){ //折半查找mid = (low + high)/2; //取中间点if(A[mid]>A[0]) //查找左半子表high = mid - 1;else //查找右半子表low = mid + 1;}for(j=i-1; j>high+1;--j) //统一后移元素,空出插入位置A[j+1] = A[j];A[high+1] = A[0]}
}
-
与直接插入排序相比,比较关键字的次数减少了,但是移动元素的次数没有变,时间复杂度仍然是O(n²)
-
对链表进行插入排序
移动元素的次数变少了,因为只需要修改指针,不需要依次右移;
但是关键字对比的次数依然是O(n²)数量级,因此整体看来时间复杂度仍然是O(n²)
总结

8.2.3 希尔排序


思路: 先追求表中元素的部分有序,再逐渐逼近全局有序;
更适用于基本有序的排序表和数据量不大的排序表,仅适用于线性表为顺序存储的情况
代码实现
void ShellSort(ElemType A[], int n){//A[0]为暂存单元for(dk=n/2; dk>=1; dk=dk/2) //步长递减(看题目要求,一般是1/2for(i=dk+1; i<=n; ++i)if(A[i]<A[i-dk]){A[0]=A[i];for(j=i-dk; j>0&&A[0]<A[j];j-=dk)A[j+dk]=A[j]; //记录后移,查找插入的位置A[j+dk]=A[0;] //插入}
}i++会切换着处理每个子表
算法效率分析
- 空间效率:空间复杂度=O(1)
- 时间效率: 最坏情况下时间复杂度=O(n²)
- 稳定性:希尔排序是一种不稳定的排序方法

8.3 交换排序
基于“交换”的排序根据序列中两个元素关键字的比较结果来对换这两个记录再序列中的位置;
8.3.1冒泡排序

第一趟排序使关键字值最小的一个元素“冒”到最前面(其最终位置)—— 每趟冒泡的结果是把序列中最小元素放到序列的最终位置,这样最多做n-1趟冒泡就能把所有元素排好序;
为保证稳定性,关键字相同的元素不交换;

代码实现
//交换
void swap(int &a,int&b){int temp=a;a=b;b=temp;
}//冒泡排序
void BubbleSort(int A[],int n){for(int i=0;i<n-1;i++){ bool flag=false; //表示本趟冒泡是否发生交换的标志for(int j=n-1;j>i;j--) //一趟冒泡过程if(A[j-1]>A[j]){ //若为逆序swap(A[j-1],A[j]); //交换flag=true;}if(flag==false)return; //本趟遍历后没有发生交换,说明表已经有序}
}
算法效率分析
- 空间复杂度:O(1)
- 时间复杂度
- 最好情况 (有序) :只需要一趟排序,比较次数=n-1,交换次数=0,最好时间复杂度=O(n)
- 最坏情况 (逆序) :比较次数 = (n-1)+(n-2)+…+1 = n(n-1)/2 = 交换次数,最坏时间复杂度 = O(n²),平均时间复杂度 = O(n²)
- 交换次数和移动次数不是一个概念


冒泡排序可以用于链表、顺序表
8.3.2快速排序(了解栈的过程)
每一趟排序都可使一个中间元素确定其最终位置
用一个元素(不一定是第一个)把待排序序列“划分”为两个部分,左边更小,右边更大,该元素的最终位置已确认


算法实现(重点)
//快速排序
void QuickSort(int A[],int low,int high){if(low<high){ //递归跳出的条件int pivotpos=Partition(A,low,high); //划分QuickSort(A,low,pivotpos-1); //划分左子表QuickSort(A,pivotpos+1,high); //划分右子表}
}//用第一个元素将待排序序列划分为左右两个部分
int Partition(int A[],int low,int high){int pivot=A[low]; //第一个元素作为枢轴while(low<high){while(low<high&&A[high]>=pivot) --high; A[low]=A[high]; //比枢轴小的元素移动到左端while(low<high&&A[low]<=pivot) ++low; A[high]=A[low]; //比枢轴大的元素移动到右端} A[low]=pivot; //枢轴元素存放到最终位置return low; //返回存放枢轴的最终位置
}
算法效率分析
每一层的QuickSort只需要处理剩余的待排序元素,时间复杂度不超过O(n);




-
若每次选中的“枢轴”将待排序序列划分为均匀的两个部分,则递归深度最小,算法效率最高
-
若每次选中的“枢轴”将待排序序列划分为很不均匀的两个部分,则会导致递归深度增加,算法效率变低
-
若初始序列有序或逆序,则快速排序的性能最差(因为每次选择的都是最靠边的元素)


8.4 选择排序
每一趟结束就会有一个元素的左边是全小于等于右边是全大于等于

8.4.1 简单选择排序

n个元素的简单选择排序需要n − 1趟处理
最后剩一个不用再处理(最后一个一定是最值)
算法实现
//交换
void swap(int &a,int&b){int temp=a;a=b;b=temp;
}//简单选择排序
void SelectSort(int A[],int n){for(int i=0;i<n-1;i++){ //一共进行n-1趟int min=i; //记录最小元素位置for(int j=i+1;j<n;j++) //在A[i...n-1]中选择最小的元素if(A[j]<A[min]) min=j; //更新最小元素位置if(min!=i) swap(A[i],A[min]); //封装的swap()函数共移动元素3次}
}
算法性能分析


8.4.2 堆排序

堆的定义


建立大根堆
大根堆:根≥ 左 右
-
思路:把所有非终端结点都检查一遍,是否满足大根堆的要求,如果不满足,则进行调整
-
检查当前结点是否满足根≥ \ge≥左,右。若不满足,将当前结点与更大的一个孩子互换
-
若元素互换破坏了下一级的堆,则采用相同的方法继续往下调整(小元素不断“下坠”)




代码实现
//建立大根堆
void BuildMaxHeap(int A[],int len){for(int i=len/2;i>0;i--){ //从后往前调整所有非终端结点HeadAdjust(A,i,len);}
}//将以 k 为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len){A[0]=A[k]; //A[0]暂存子树的根结点for(int i=2*k;i<=len;i*=2){ //沿key较大的子结点向下筛选if(i<len&&A[i]<A[i+1])i++; //取key较大的子结点的下标if(A[0]>=A[i]) break; //筛选结束else{A[k]=A[i]; //将A[i]调整到双亲结点上k=i; //修改k值,以便继续向下筛选}}A[k]=A[0] //将被筛选结点的值放入最终位置
}
堆排序的完整逻辑

//建立大根堆
void BuildMaxHeap(int A[],int len)//将以k为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len)//堆排序的完整逻辑
void HeapSort(int A[],int len){BuildMaxHeap(A,len); //初始建堆for(int i=len;i>1;i--){ //n-1趟的交换和建堆过程 swap(A[i],A[1]); //堆顶元素和堆底元素交换HeadAdjust(A,1,i-1); //把剩余的待排序元素整理成堆}
}
算法效率分析





堆排序是不稳定的
8.4.3 堆的插入删除

-
在堆中插入新元素
对于小根堆,新元素放到表尾,与父节点对比,若新元素比父节点更小,则将二者互换。新元素就这样一路“上升”,直到无法继续上升为止 -
在堆中删除元素
被删除的元素用堆顶元素替代,然后让该元素不断“下坠”,直到无法下坠为止
8.5 归并排序(Merge Sort)内外部排序


Merge(归并/合并)
- 归并:把两个或多个已经有序的序列合并成一个
“2路”归并 —— 每选出一个小元素就需对比关键字1次。“4路”归并 —— 每选出一个小元素就需对比关键字3次。故m路归并,每选出一个元素需要对比关键字m − 1次
归并排序(手算模拟)
在内部排序中一般采用2路归并
核心操作:把数组内的两个有序序列归并为一个

代码实现
int *B=(int *)malloc(n*sizeof(int)); //辅助数组B//A[low...mid]和A[mid+1...high]各自有序,将两个部分归并
void Merge(int A[],int low,int mid,int high){int i,j,k;for(k=low,k<=high;k++)B[k]=A[k]; //把A中所有元素复制到B中for(i=low,j=mid+1,k=i;i<=mid&&j<=high,k++){if(B[i]<=B[j]) A[k]=B[i++]; //将较小值复制到A中elseA[k]=B[j++];}//forwhile(i<=mid) A[k++]=B[i++]; while(j<=high) A[k++]=B[j++];
}void MergeSort(int A[],int low,int high){if(low<high){int mid=(low+high)/2; //从中间划分MergeSort(A,low,mid); //对左半部分归并排序MergeSort(A,mid+1,high); //对右半部分归并排序Merge(A,low,mid,high); //归并}//if
}

算法效率分析

而递归栈的空间复杂度是 l o g 2 n log_2^n log2n,选取最大的就是辅助数组带来的空间复杂度
两个元素相等时,优先使用靠前的那个。归并排序是稳定的
8.6 基数排序(Radix Sort)

基数排序
可见基数排序不是基于“比较”的排序算法
排序方式








递减

递增

算法效率分析
基数排序通常基于链式存储实现



基数排序的应用


各种内部排序算法的比较及应用



内部排序算法的应用


8.7 外部排序
8.7.1 归并排序的实现

内存、外存之间的数据交换

外部排序原理










时间开销分析
读写都是一块一块

优化

多路归并

减少初始归并段数量




什么是多路平衡归并?

图没错,定义错了
图错的例子,如下

8.7.2 败者树

败者树的构造


败者树的使用


败者树在多路平衡归并中的应用


败者树的实现思路
从不同位置插入元素,会经过不同层数,也就是不同的对比次数

8.7.3 置换-选择排序





8.7.4 最佳归并树

归并树的性质

构造2路归并的最佳归并树

多路归并的情况





添加虚段的数量

数据结构结束

相关文章:
数据结构 排序
目录 第八章 排序8.1排序的基本概念1. 概念2. 排序算法的分类 8.2 插入排序8.2.1 直接插入排序8.2.2 算法效率分析8.2.2 折半插入排序总结8.2.3 希尔排序 8.3 交换排序8.3.1冒泡排序8.3.2快速排序(了解栈的过程) 8.4 选择排序8.4.1 简单选择排序8.4.2 堆…...
Cpp/Qtday050912cpp基础
目录 实现一个图形类(Shape),包含受保护成员属性:周长、面积, 公共成员函数:特殊成员函数书写 定义一个圆形类(Circle),继承自图形类,包含私有属性&#x…...
Git diff 使用 vimdiff 对比差异
在Ubuntu中使用Git时,可使用命令行的git diff命令来对比两次提交的差异,但是这种对比查看方式无法直观地查看修改的差异,在对比和查看时不太方便。 可以使用vimdiff作为Git diff的对比工具,这样就方便了许多,Git的配置…...
c小白勇闯结构体!!!!
目录 1.结构体类型的声明 1.结构的基础 2.结构体的声明 3.结构体成员的类型 4结构体变量的定义和初始化 2.结构体成员的访问 3.结构体传参 1.结构体类型的声明 1.结构的基础 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量 结构体变量的创…...
【DevOps核心理念基础】3. 敏捷开发最佳实践
一、敏捷开发最佳实践 1.1 项目管理 1.2 需求管理 1.3 技术架构 1.4 技术开发 1.5 测试 二、敏捷开发最佳实践 2.1 敏捷开发的执行细节 三、全面的DevOps工具链 四、版本控制和协作开发工具 4.1 集中式版本控制工具 4.2 分布式版本控制工具 一、敏捷开发最佳实践 …...
二进制、数位dp:0912T3
考虑题目转化,二进制下满足 i ⊆ j , ( i x ) ⊆ ( j y ) i\subseteq j,(ix)\subseteq (jy) i⊆j,(ix)⊆(jy) 这显然是个数位dp形式 考虑枚举每一位与进位, d p k , p 1 , p 2 dp_{k,p_1,p_2} dpk,p1,p2 表示第 k − 1 k-1 k−1 位向第 k k…...
Java基于SpringBoot+Vue的 4S店车辆管理系统
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 功能总览4 系统设计4.1 系统设计主要功能4.2 数据库设计4.2.1 数据库设计规范4.2…...
助力智能化公路养护,基于YOLOv5s集成SPD-BIFPN-SE开发构建公路开裂检测识别系统
在前文中我们尝试构建了在隧道、涵洞尝尽下的自动智能化养护巡查相关的模型,进行了实地测试评估,感兴趣的话可以自行移步阅读即可: 《基于轻量级YOLOv5s开发构建隧道基建裂痕、脱落等缺陷问题检测系统》 本文的想法是相近的,核心…...
C++--day5
实现一个图形类(Shape),包含受保护成员属性:周长、面积, 公共成员函数:特殊成员函数书写 定义一个圆形类(Circle),继承自图形类,包含私有属性:半…...
Django应用部署实战:从开发到生产,全程解析
部署架构图 版本说明 Centos 7.4 Python 3.6.4 Django 2.0.2 Channels 2.0.0 MySql 5.7 uWSGI Nginx 1.12.2 部署前 1、更新系统环境 yum install epel-release 2、安装所有的开发工具包 yum groupinstall -y “Development tools” 一、安装python 3.6.4 1、下载 cd /usr/…...
群晖NAS如何在内网部署HTTPS服务让浏览器信任证书
前言 最近在折腾内部部署Web服务。通过Vue实现一个H5的内部的管理服务。但在实际部署过程中由于种种原因,必须部署成Https服务。但在部署成Https服务后,由于没有HTTPS证书,每次进入页面都会被浏览器拦截。使用起来非常不便。于是开始各种Goo…...
crAPI靶场学习记录
靶场搭建 [靶场下载地址](我fork了一份) docker安装,笔者是用的wsldocker. [lab0:**初始账户 **] 注册一个账户,邮箱为[APIqq.com],密码为Admin123 登陆后访问对应IP的8025端口,接收邮件获取车辆信息。 [lab1:**访问其它用户车…...
知识图谱实战应用28-基于py2neo的ICD-11疾病分类的知识图谱的查询与问答实战应用
大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用28-基于py2neo的ICD-11疾病分类的知识图谱的查询与问答实战应用。使用基于py2neo的ICD-11疾病分类知识图谱,我们能够像探索一座生物医学宇宙般,穿梭在各种疾病之间。这个神奇的图谱可以帮助我们揭示各种疾病之间复杂而…...
20.Xaml GroupBox控件 ---->带标题的内容控件
1.运行效果 2.运行源码 a.Xaml源码 <Window x:Class="testView.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mic…...
基于CycleGAN的山水风格画迁移
基于CycleGAN的山水风格画迁移 1、简介 1.1 研究背景及意义 绘画是人类重要的一种艺术形式,其中中国的山水画源远流长,具有丰富的美学内涵,沉淀着中国人的情思。游山玩水的大陆文化意识,以山为德、水为性的内在修为意识&#x…...
@Cacheable 注解
1. 功能说明 Cacheable 注解在方法上,表示该方法的返回结果是可以缓存的。也就是说,该方法的返回结果会放在缓存中,以便于以后使用相同的参数调用该方法时,会返回缓存中的值,而不会实际执行该方法。 注意,这…...
vue3+ts项目打包后的本地访问
注意:打包之后不可直接点击html访问,需要给项目安装本地服务! 1、安装servenpm i -g serve 2、打包项目npm run build 生成dist文件夹 3、本地访问serve dist 运行service dist之后的控制台 可复制下方的地址运行打包后的项目,运行…...
探索程序员需要掌握的算法?
文章目录 一:引言二:常见算法介绍三:重点算法总结 🎉欢迎来到数据结构学习专栏~探索程序员需要掌握的算法? ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨博客主页:IT陈寒的博客🎈该系列文章…...
性能测试 —— Jmeter定时器
固定定时器 如果你需要让每个线程在请求之前按相同的指定时间停顿,那么可以使用这个定时器;需要注意的是,固定定时器的延时不会计入单个sampler的响应时间,但会计入事务控制器的时间 1、使用固定定时器位置在http请求中…...
mp4视频太大怎么压缩?几种常见压缩方法
mp4视频太大怎么压缩?科技的飞速发展使得视频成为人们生活中不可或缺的一部分。然而,随着视频质量的不断提高,视频文件的大小也与日俱增,给我们的存储和传输带来了巨大的挑战和困扰。特别是MP4格式的视频,由于其出色的…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
