目录

0 摘要

1 引言

2 排序算法

2.1 排序算法的分类

2.1.1 稳定排序与不稳定排序

2.1.2 内排序与外排序

2.2 排序算法的性能评价

2.3 内排序和外排序的举例

2.4 内排序的四种分类

3 算法比较

3.1 冒泡排序

3.2 简单选择排序

3.3 直接插入排序

3.4 希尔排序

3.5 堆排序

3.6 归并排序

3.7 快速排序

4 总结回顾

5 例题介绍

6 文章结尾

7 文件分享


0 摘要

排序是计算机程序设计大赛中最常见,最基础却又是最为重要的知识点。在实际生活中也有着极其重要的作用。主要介绍排序的种类:希尔排序、冒泡排序、快速排序、堆排序等等,以及各种算法的比较及其适应的情况。


1 引言

假设含有n个记录的序列为{r1,r2,...rn},其相应的关键字分别为{k1,k2,...,kn},需确定1,2,...,n的一种排列p1,p2,...,pn,使其相应的关键字满足kp1≤kp2≤...≤kpn非递减(或非递增)关系,及时地序列称为一个按关键字有序的序列{rp1,rp2,...,rpn},这样的操作就称为排序。


2 排序算法

2.1 排序算法的分类

2.1.1 稳定排序与不稳定排序

稳定排序:对任意一组数据元素序列,使用某种排序算法对它进行按照关键字的排序,若相同关键字的前后位置关系在排序前与排序后保持一致,则称此排序方法时稳定的。
不稳定排序:对任意一组数据元素序列,使用某种排序算法对它进行按照关键字的排序,若相同关键字的前后位置关系在排序前与排序后不能保持一致,则称此排序方法时不稳定的。
例如:关键字序列{3(1),4,2,3(2),1},经过排序算法后变为{1,2,3(1),3(2),4},则次排序方法是稳定的;若变为{1,2,3(2),3(1),4},则次排序方法时不稳定的。

2.1.2 内排序与外排序

按照排序过程中所涉及的存储器的不同可分为内排序和外排序。
内排序是指待排序序列完全存放在内存中进行的排序过程,这种方法适合数量不太大的数据元素的排序。
外排序是指待排序的数据元素非常多,以至于它们必须存储在外部存储器上,这种排序过程中需要在内外存之间多次交换数据才能进行,这样的排序称为外排序。

2.2 排序算法的性能评价

时间复杂度:排序算法的时间开销是衡量其好坏的最重要的标志。高效率的内排序算法应该是具有尽可能少的关键字比较次数和尽可能少的记录移动次数。
空间复杂度:辅助存储空间是除了存放待排序所占用的存储空间之外,执行算法所需要的其他存储空间。当排序算法中使用的额外内存空间与要排序数据元素的个数n无关时,其空间 复杂度为O(1),大多数排序算法的空间复杂度是O(1),也有一些时间复杂度性能好的排序算法,其空间复杂度会达到O(n)。
稳定性,即对任意一组数据元素序列,使用某种排序算法对它进行按照关键字的排序,若相同关键字的前后位置关系在排序前与排序后保持一致,则称此排序方法时稳定的。稳定的排序算法是应用问题所希望的,因此,排序算法的稳定性是衡量排序算法好坏的一个重要指标。

2.3 内排序和外排序的举例

内排序:插入排序、交换排序、选择排序和归并排序。
外排序:磁盘排序中的多路平衡归并排序、置换-选择排序和最优归并树。

2.4 内排序的四种分类


3 算法比较

3.1 冒泡排序

冒泡排序是一种交换排序,他的基本思想是:两两比较相邻记录的关键字,如果反序则交换,知道没有反序的记录为止。对于标准的冒泡排序的代码,我觉得应该有改进的地方,还是可以优化的,(如果序列有序,但是标准算法依然还是进行大量比较,就显得很多余)。那么我就给出优化后的代码:

void BubbleSort2(SqList *L)
{Int i, j;Status flag = TRUE;for (i = 1; i < L->length && flag; i++){Flag = FALSE;for (j = L->length - 1; j >= i; j--)
If(L->r[j] > L -> r[j+1]
{Swap(L, j, j + 1);Flag = TRUE;
}}
}

代码改动的关键是在i变量的for循环中,增加了对flag是否为TRUE的判断。

3.2 简单选择排序

简单选择排序法(Simple Selection Sort)就是通过n-i次关键字间的比较,从 n-i+1个记录中选出关键字最小的记录,并和第i (1<i<n)个记录交换之。

void SelectSort(SqList *L)
{int i, jrmin;for (i <= l; i < L->length; i++){min = i; for (j = i + 1; j <= L->length; j++) /*循环之后的数据 */{if (L->r[min] > L->r[j])min = j;}if (i != min)swap(L, i, min);}
}

3.3 直接插入排序

直接插入排序(Straight Insertion Sort)的基本操作是将一个记录插入到已经排 好序的有序表中,从而得到一个新的、记录数增1的有序表。

void InsertSort(SqList *L)
{int i, j;for (i = 2; i < -L->length; i++){if (L->r[i] < L->r(i - 1))L->r[O] = L->r[i];}for (j = i - 1; L->r[j] > L->r[0]; j--){L->r[j + 1] = L->r(j);L->r[j + 1] - L->r[0];}
}

3.4 希尔排序

现在,我要讲解的算法叫希尔排序(Shell Sort)o希尔排序是D.LShell于1959年 提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是年n的平方的,希尔排序算法是突破这个时间复杂度的第一批算法之一。
void ShellSort(SqList *L)
{int i , j;int increment = L->length;do{increment = increment / 3 + l;for (i = increment + l; i <= L->length; i++)if (L->r[i] < L->r[i - increment]){L->r[0] - L->r[i];for (j - (i - increment); j > 0 && L->r[0] < L->r[j]; j <= increment)L->r[j + increment] = L->r[j]; /*记录后移,查找插入位置 */L->r[j + increment] = L->r[0];     /* 插入 */}} while (increment > l);
}

3.5 堆排序

堆排序(Heap Sort)就是利用堆(假设利用大顶堆)进行排序的方法。它的基本思想是,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根 结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,便能得到一个有序序列了。

void HeapSort(SqList *L)
{int i;for (i = L->length / 2; i > 0; i--)HeapAdj ust(L, i, L->length);for (i = L->length; i > l; i--){swap(L.l, i);HeapAdjust(L, lri - 1);}
}

3.6 归并排序

归并” 一词的中文含义就是合并、并入的意思,而在数据结构中的定义是将两个 或两个以上的有序表组合成一个新的有序表。

归并排序(Merging Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2] ([x]表示不小于x的最小整数)个长度为2或1的有 序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止, 这种排序方法称为2路归并排序。

void MSort(int SR[], int TRI[], int s, int t)
{int m;int TR2[MAXSIZE + 1];if (s == t)TRl[s] = SR[s];else{m = (s + t) / 2;MSort(SR, TR2, s, m);MSort(SR, TR2, m + 1, t);Merge(TR2, TR1, s, m, t); /*将TR2[s.・m]和TR2[m+1..仁]*/}
}

3.7 快速排序

快速排序(Quick Sort)的基本思想是:通过一趟排序将待排记录分割成独立的 两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部 分记录继续进行排序,以达到整个序列有序的目的。

void QSort(SqList *Lr, int low, int high)
{int pivot;if (low < high){pivot = Partition(L, low, high);QSort(L, low, pivot - 1);QSort(L, pivot + 1, high);}
}

4 总结回顾

本章文只是在讲排序,我们需要对已经提到的各个排序算法进行对比来总结回 顾。

首先我们讲了排序的定义,并提到了排序的稳定性,排序稳定对于某些特殊需求 来说是至关重要的,因此在排序算法中,我们需要关注此算法的稳定性如何。

我们根据将排序记录是否全部被放置在内存中,将排序分为丙排序与外排序两 种,外排序需要在内外存之间多次交换数据才能进行。我们本章主要讲的是内排序的 算法。

根据排序过程中借助的主要操作,我们将内排序分为:插入排序、交换排序、选 择排序和归并排序四类。之后介绍的7种排序法,就分别是各种分类的代表算法。

我们对各种排序方法进行总结,对比。

通过这个表,我们直接的能进行下列的分析:

从算法的简单性来看,我们将7种算法分为两类:

  • 简单算法:冒泡、简单选择、直接插入。
  • 改进算法:希尔、堆、归并、快速。

从平均情况来看,显然最后3种改进算法要胜过希尔排序,并远远胜过前3种简 单算法。

从最好情况看,反而冒泡和直接插入排序要更胜一筹,也就是说,如果你的待排 序序列总是基本有序,反而不应该考虑4种复杂的改进算法。

从最坏情况看,堆排序与归并排序又强过快速排序以及其他简单排序。

从这三组时间复杂度的数据对比中,我们可以得出这样一个认识。堆排序和归并 排序就像两个参加奥数考试的优等生,心理素质强,发挥稳定。而快速排序像是很情 绪化的天才,心情好时表现极佳,碰到较糟糕环境会变得差强人意。但是他们如果都 来比赛计算个位数的加减法,它们反而算不过成绩极普通的冒泡和直接插入。

从空间复杂度来说,归并排序强调要马跑得快,就得给马吃个饱。快速排序也有 相应的空间要求,反而堆排序等却都是少量索取,大量付出,对空间要求是0(1)。如 果执行算法的软件所处的环境非常在乎内存使用量的多少时,选择归并排序和快速排 序就不是一个较好的决策了。

从稳定性来看,归并排序独占鳌头,我们前面也说过,对于非常在乎排序稳定性 的应用中,归并排序是个好算法。

从待排序记录的个数上来说,待排序的个数n越小,采用简单排序方法越合适。 反之,n越大,采用改进排序方法越合适。这也就是我们为什么对快速排序优化时, 增加了一个阀值,低于阀值时换作直接插入排序的原因。


5 例题介绍

我们可以使用基于快速排序的方法,求出「出现次数数组」的前k大的值。
在对数组arr[做快速排序的过程中,我们首先将数组划分为两个部分arri...q-1]与arrq+1.j,并使得arriq-1中的每一个值都不超过arr[q],且arrq+1..j]中的每一个值都大于arrg]。于是,我们根据k与左侧子数组arri...q-1]的长度(为q-i)的大小关系:
·如果k≤q-i,则数组arrl...r]前k大的值,就等于了数组arri...q-1前k大的值。
。否则,数组arrlr]前k大的值,就等于左侧子数组全部元素,加上右侧了数组arrq+1...jj中前 k-(q-i)大的值。
原版的快速排序算法的平均时间复杂度为O(NlogN)。我们的算法中,每次只需在其中的一个分支递归即可,因此算法的平均时间复杂度降为O(N)。

代码如下:

#include <bits/stdc++.h>
using namespace std;
struct hash_table
{int key;int val;UT_hash_handle hh;
};typedef struct hash_table *hash_ptr;struct pair
{int first;int second;
};void swap(struct pair *a, struct pair *b)
{struct pair t = *a;*a = *b, *b = t;
}void sort(struct pair *v, int start, int end, int *ret, int *retSize, int k)
{int picked = rand() % (end - start + 1) + start;swap(&v[picked], &v[start]);int pivot = v[start].second;int index = start;for (int i = start + 1; i <= end; i++){if (v[i].second >= pivot){swap(&v[index + 1], &v[i]);index++;}}swap(&v[start], &v[index]);if (k <= index - start){sort(v, start, index - 1, ret, retSize, k);}else{for (int i = start; i <= index; i++){ret[(*retSize)++] = v[i].first;}if (k > index - start + 1){sort(v, index + 1, end, ret, retSize, k - (index - start + 1));}}
}int *topKFrequent(int *nums, int numsSize, int k, int *returnSize)
{hash_ptr head = NULL;hash_ptr p = NULL, tmp = NULL;for (int i = 0; i < numsSize; i++){HASH_FIND_INT(head, &nums[i], p);if (p == NULL){p = malloc(sizeof(struct hash_table));p->key = nums[i];p->val = 1;HASH_ADD_INT(head, key, p);}else{p->val++;}}struct pair values[numsSize];int valuesSize = 0;HASH_ITER(hh, head, p, tmp){values[valuesSize].first = p->key;values[valuesSize++].second = p->val;}int *ret = malloc(sizeof(int) * k);*returnSize = 0;sort(values, 0, valuesSize - 1, ret, returnSize, k);return ret;
}

6 文章结尾

本篇主要详述了排序算法的概要以及排序算法在相关竞赛的应用。陆续会更新其他竞赛中常用的一些知识点。


7 文件分享

如果大家需要Word或者PDF版本,使用以下链接。

链接:https://pan.baidu.com/s/1ZE0VwwFqTdbk7WyMAUZ3aA 
提取码:lh91


排序相关算法在计算机程序设计竞赛中的研究相关推荐

  1. 中南大学计算机程序设计实践,我校在湖南省第七届大学生计算机程序设计竞赛中载誉归来...

    9月15日,湖南省第七届大学生计算机程序设计竞赛在湖南农业大学成功举办.我校代表队在本次竞赛中载誉而归,派出的4支参赛队伍中,一支队伍夺得一等奖,三支队伍夺得二等奖. 湖南省大学生计算机程序设计竞赛是 ...

  2. 长沙计算机学院欧阳登轶,我校学生在2020年湖南省第十六届“强智杯”大学生计算机程序设计竞赛中喜获一等奖...

    10月17-18日,湖南省第十六届"强智杯"大学生计算机程序设计竞赛在长沙理工大学落下帷幕.本次大赛由湖南省教育厅主办,分为程序设计类.应用开发类和机器人类三项赛事.此次竞赛全省4 ...

  3. 计算机算法基础_强智科技继续冠名第十六届“强智杯”湖南省大学生计算机程序设计竞赛...

    2020年10月17-18日,第十六届"强智杯"湖南省大学生计算机程序设计竞赛在长沙理工大学成功举办,本次竞赛由省教育厅主办.省高教学会计算机教育专业委员会协办.长沙理工大学承办, ...

  4. 计算机信息技术奥赛实践,我校计算机科学与信息技术学院学生在黑龙江省大学生程序设计竞赛中取得优异成绩...

    原标题:我校计算机科学与信息技术学院学生在黑龙江省大学生程序设计竞赛中取得优异成绩 5月12日,由黑龙江省计算机学会主办.哈尔滨工业大学承办的第十四届黑龙江省大学生程序设计竞赛在哈尔滨工业大学举行,来 ...

  5. 宁波医院计算机试题及答案,(宁波市第25届小学生计算机程序设计竞赛试题及答案.doc...

    (宁波市第25届小学生计算机程序设计竞赛试题及答案 宁波市第25届中小学生程序设计竞赛组初赛试题 1.在宁波市中小学生程序设计比赛复赛(上机编程)时,以下不能使用的编程语言是: (A)Turbo Pa ...

  6. 宁波市第23届中小学生计算机程序设计竞赛初赛,宁波市第24届中小学生计算机程序设计竞赛初赛试题(小学组)...

    宁波市第24届中小学生计算机程序设计竞赛初赛试题(小学组) 更多试题请登陆nb.aoshu.com2009年宁波市第24届中小学生计算机程序设计竞赛一.选择题(1.5每题)1.以下不属于程序的基本结构 ...

  7. 程序设计竞赛中常用的STL汇总

    程序设计竞赛中常用的STL汇总 说明:文章篇幅有些长,请根据需要和目录选择性阅读!以下的所有STL模板按照C++0x/11的标准来的,部分含有C++98的特性.在刷题或者考试的时候,请仔细看是否支持C ...

  8. 怀化学院计算机科学张显老师,怀化学院第十二届大学生计算机程序设计竞赛暨2019年湖南省第十五届大学生程序设计大赛选拔赛完美落幕...

    原标题:怀化学院第十二届大学生计算机程序设计竞赛暨2019年湖南省第十五届大学生程序设计大赛选拔赛完美落幕 2019年6月9日,由我校教务处主办,计算机科学与工程学院.怀化学院ACM协会承办的怀化学院 ...

  9. 第29届宁波市中小学生计算机程序设计竞赛复赛名单公布,宁波市第23届中小学生计算机程序设计竞赛复赛试题(小学组)...

    <宁波市第23届中小学生计算机程序设计竞赛复赛试题(小学组)>由会员分享,可在线阅读,更多相关<宁波市第23届中小学生计算机程序设计竞赛复赛试题(小学组)(7页珍藏版)>请在人 ...

最新文章

  1. 【重要预警】“永恒之蓝”漏洞又现新木马 组成僵尸网络挖矿虚拟货币
  2. 台湾澎湖县启动返乡包机 春节疏运增加25个航班
  3. 智能优化算法之蚁群算法(1)
  4. 用 Flask 来写个轻博客 (7) — (M)VC_models 的关系(many to many)
  5. html5中在图片上打字的语法,HTML5 canvas 基本语法
  6. 【HarmonyOS】开发工具【DevEco Studio】下载安装
  7. 泊松分布的分布函数_10分钟了解泊松分布
  8. leetcode240. 搜索二维矩阵 II
  9. 2020-08-22 OpenWRT 脚本修改网卡MAC
  10. 形式的化简与和式的展开
  11. Dataguard之redo传输服务
  12. Layui第三方扩展LAY_EXCEL导出数据表格的数据
  13. Java、Python网页项目,纯前端项目,无后端参考代码,谨慎下载,全网可视性超强Web项目,免费源码,Js、Html、Css组合网页,可衔接数据库,数据可自行修改,可使用SSM、SpringBoo
  14. mac配置OpenGL超级宝典(第7版)环境
  15. 【数学建模】CUMCM-2011B model5 围捕方案确定
  16. html绑定drag事件,html 5自带drag属性详解
  17. 电脑磁盘右键没有新建文件夹???
  18. SNMPWALK 命令
  19. PHP中 字符串 常用函数
  20. C语言【程序21】 题目:打印出如下图案(菱形)

热门文章

  1. java毕业设计企业员工考勤系统的设计与实现源码+lw文档+mybatis+系统+mysql数据库+调试
  2. Centos 更换静态IP脚本
  3. python免费下载歌曲_实现python批量下载网易云音乐的免费音乐
  4. 编码(字符串) SDUT
  5. python中for循环打印菱形_Python 使用双重循环打印图形菱形操作
  6. 中国日期转化标准日期(YYYY-MM-dd)
  7. PWM脉冲宽度调制——它是什么?
  8. electron打开系统默认浏览器
  9. Linux资源控制-使用cgroup控制CPU和内存
  10. PDPS软件:机器人行走轴虚拟仿真操作方法,即外部轴添加与配置