数据结构-排序算法总结与感悟
数据结构-排序算法总结
一,排序的基本概念
排序:有n个记录的序列{R1,R2,…,Rn},其相应关键字的序列是{K1,K2, …,Kn },相应的下标序列为1,2,…, n。通过排序,要求找出当前下标序列1,2,…, n的一种排列p1,p2, …,pn,使得相应关键字满足如下的非递减(或非递增)关系,即:Kp1≤ Kp2≤…≤ Kpn,这样就得到一个按关键字有序的记录序列:{Rp1, Rp2, …, Rpn}。
1、内部排序:整个排序过程完全在内存中进行,称为内部排序。
2、外部排序:由于待排序记录数据量太大,内存无法容纳全部数据,排序需要借助外部存储设备才能完成,称为外部排序。
3、在排序过程中,一般进行两种基本操作:
①比较两个关键字的大小。
②将记录从一个位置移动到另一个位置。
二,插入类排序
(一) 思想:在一个已经排好序的序列中,将未被排进的元素按照原先的规定插入到指定位置。
(二) 分类:
1、 直接插入排序:
① 思想:最基本的插入排序,将第i个插入到前i-1个中的适当位置。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。循环条件while(r[0].key < r[j].key)保证的。
⑤ 程序:
- void InsSort(RecordType r[], int length)
- {
- for(i = 2; I <= length; i++)
- {
- r[0] = r[i];
- j = i – 1;
- while(r[0].key < r[j].key)
- {
- r[j + 1] = r[j]; j = j – 1;
- }
- r[j+1] = r[0];
- }
三,折半插入排序
① 思想:因为是已经确定了前部分是有序序列,所以在查找插入位置的时候可以用折半查找的方法进行查找,提高效率。
② 时间复杂度:比较时的时间减为O(n㏒n),但是移动元素的时间耗费未变,所以总是得时间复杂度还是O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。
⑤ 程序:
- void BinSort(RecordType r[], int length)
- {
- for(i = 2; i <= length; i++)
- {
- x = r[i];
- low = 1; high = i – 1;
- while(low <= high)
- {
- mid = (low + high) / 2;
- if(x.key < r[mid].key)
- high = mid – 1;
- else
- low = mid – 1;
- }
- for(j = i – 1; j >= low; --j)
- r[j + 1] = r[j];
- r[low] = x;
- }
- }
四,希尔排序
① 思想:又称缩小增量排序法。把待排序序列分成若干较小的子序列,然后逐个使用直接插入排序法排序,最后再对一个较为有序的序列进行一次排序,主要是为了减少移动的次数,提高效率。原理应该就是从无序到渐渐有序,要比直接从无序到有序移动的次数会少一些。
② 时间复杂度:O(n的1.5次方)
③ 空间复杂度:O(1)
④ 稳定性:不稳定排序。{2,4,1,2},2和1一组4和2一组,进行希尔排序,第一个2和最后一个2会发生位置上的变化。
⑤ 程序:
- void ShellInsert(RecordType r[], int length, int delta)
- {
- for(i = 1 + delta; i <= length; i++)/*1+delta为第一个子序列的第二个元素的下表*/
- if(r[i].key < r[1 - delta].key)
- {
- r[0] = r[i];
- for(j = i – delta; j > 0 && r[0].key < r[j].key; j -=delta)
- r[j + delta] = r[j];
- r[j + delta] = r[0];
- }
- }
- void ShellSort(RecordType r[], int length, int delta[], int n)
- {
- for(i = 0; i <= n – 1; ++i)
- ShellInsert(r, length, delta[i]);
- }
五,交换类排序
(一) 思想:通过交换逆序元素进行排序的方法。
(二) 分类:
1、 冒泡排序:
① 思想:反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。第一趟,从第一个数据开始,比较相邻的两个数据,(以升序为例)如果大就交换,得到一个最大数据在末尾;然后进行第二趟,只扫描前n-1个元素,得到次大的放在倒数第二位。以此类推,最后得到升序序列。如果在扫描过程中,发现没有交换,说明已经排好序列,直接终止扫描。所以最多进行n-1趟扫描。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。
⑤ 程序:
- void BubbleSort(RecordType r[], int length)
- {
- n = length;
- change = TRUE;
- for(i = 1; i <= n – 1 && change; i++)
- {
- change = FALSE;
- for(j = 1; j <= n – I; ++j)
- if(r[j].key > r[j + 1].key)
- {
- x = r[j];
- r[j] = r[j + 1];
- r[j + 1] = x;
- change = TRUE;
- }
- }
- }
六,快速排序
① 思想:冒泡排序一次只能消除一个逆序,为了能一次消除多个逆序,采用快速排序。以一个关键字为轴,从左从右依次与其进行对比,然后交换,第一趟结束后,可以把序列分为两个子序列,然后再分段进行快速排序,达到高效。
② 时间复杂度:平均T(n) = O(n㏒n),最坏O(n²)。
③ 空间复杂度:S(n) = O(㏒n)。
④ 稳定性:不稳定排序。{3, 2, 2}
⑤ 程序:
- void QKSort(RecordType r[], int low, int high)
- {
- int pos;
- if(low < high)
- {
- pos = QKPass(r, low, high);
- QKSort(r, low, pos - 1);
- QKSort(r, pos + 1, high);
- }
- }
- int QKPass(RecordType r[], int left, int right)
- {
- RecordType x;
- int low, high;
- x = r[left];
- low = left;
- high = right;
- while(low < high)
- {
- while(low < high && r[high].key >= x.key)
- high--;
- if(low < high)
- {
- r[low] = r[high];
- low++;
- }
- while(low < high && r[low].key < x.key)
- low++;
- if(low < high)
- {
- r[high] = r[low];
- high--;
- }
- }
- r[low] = x;
- return low;
- }
七,选择类排序
(一) 思想:每一趟在n – i + 1 ( i = 1,2, … , n - 1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。
(二) 分类:
1、 简单选择排序:
① 思想:第一趟时,从第一个记录开始,通过n – 1次关键字的比较,从n个记录中选出关键字最小的记录,并和第一个记录进行交换。第二趟从第二个记录开始,选择最小的和第二个记录交换。以此类推,直至全部排序完毕。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序,{3, 3, 2}。
⑤ 程序:
- void SelectSort(RecordType r[], int length)
- {
- n = length;
- for(i = 1; i <= n - 1; i++)
- {
- k = i;
- for(j = i + 1; j <= n; i++)
- if(r[j].key < r[k],key)
- k = j;
- if(k != i)
- {
- x = r[i];
- r[i] = r[k];
- r[k] = x;
- }
- }
- }
八,树形选择排序
① 思想:为了减少比较次数,两两进行比较,得出的较小的值再两两比较,直至得出最小的输出,然后在原来位置上置为∞,再进行比较。直至所有都输出。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:较简单选择排序,增加了n-1个额外的存储空间存放中间比较结果,就是树形结构的所有根节点。S(n) = O(n)。
④ 稳定性:稳定排序。
⑤ 程序:
九,堆排序
① 思想:把待排序记录的关键字存放在数组r[1…n]中,将r看成是一刻完全二叉树的顺序表示,每个节点表示一个记录,第一个记录r[1]作为二叉树的根,一下个记录r[2…n]依次逐层从左到右顺序排列,任意节点r[i]的左孩子是r[2i],右孩子是r[2i+1],双亲是r[i/2向下取整]。然后对这棵完全二叉树进行调整建堆。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序。{5, 5, 3}
⑤ 程序:
(1) 调整堆:
- void sift(RecordType r[], int k, int m)
- {
- /*假设r[k...m]是以r[k]为根的完全二叉树,而且分别以r[2k]和r[2k+1]为根的左右子树为大根堆,调整r[k],使整个序列r[k...m]满足堆的性质*/
- t = r[k];/*暂存“根”记录r[k]*/
- x = r[k].key;
- i = k;
- j = 2 * i;
- finished = FALSE;
- while(j <= m && !finished)
- {
- if(j < m && r[j].key < r[j + 1].key)
- j = j + 1;/*若存在右子树,且右子树根的关键字大,则沿右分支“筛选”*/
- if(x >= r[j].key)
- finished = TRUE;/*筛选完毕*/
- else
- {
- r[i] = r[j];
- i = j;
- j = 2 * i;
- }/*继续筛选*/
- }
- r[i] = t;/*将r[k]填入到恰当的位置*/
- }
(2) 建初堆:
- void crt_heap(recordType r[], int length)
- {
- n = length;
- for(i = n / 2; i >= 1; --i)/*自第n/2向下取整 个记录开始进行筛选建堆*/
- sift(r, i, n);
- }
(3) 堆排序:
- void HeapSort(RecordType r[], int length)
- {
- crt_heap(r, length);
- n = length;
- for(i = n; i >= 2; --i)
- {
- b = r[1];/*将堆顶记录和堆中的最后一个记录互换*/
- r[1] = r[i];
- r[i] = b;
- sift(r, 1, i - 1);/*进行调整,使r[1…i-1]变成堆*/
- }
- }
十,归并排序
(一) 思想:
(二) 分类:
1、 归并排序:
① 思想:假设初始序列右n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2向上取整 个长度为2(n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的有序子序列。如此重复,直至得到一个长度为n的有序序列为止。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(n)。
④ 稳定性:稳定排序。
⑤ 程序:
- void Merge(RecordType r1[], int low, int mid, int high, RecordType r2[])
- {
- /*已知r1[low...mid]和r1[mid + 1...high]分别按关键字有序排列,将它们合并成一个有序序列,存放在r2[low...high]*/
- i = low;
- j = mid + 1;
- k = low;
- while((i <= mid) && (j <= high))
- {
- if(r1[i].key <= r1[j].key)
- {
- r2[k] = r1[i];
- ++i;
- }
- else
- {
- r2[k] = r1[j];
- ++j;
- }
- ++k;
- }
- while(i <= mid)
- {
- r2[k] = r1[i];
- k++;
- i++;
- }
- while(j <= high)
- {
- r2[k] = r1[j];
- k++;
- j++;
- }
- }
- void MSort(RecordType r1[], int low, int high, RecordType r3[])
- {
- /*r1[low...high]经过排序后放在r3[low...high]中,r2[low...high]为辅助空间*/
- RecordType r2[N];
- if(low == high)
- r3[low] = r1[low];
- else
- {
- mid = (low + high) / 2;
- MSort(r1, low, mid, r2);
- MSort(r1, mid + 1, high, r2);
- Merge(r2, low, mid, high, r3);
- }
- }
- void MergeSort(RecordType r[], int n)
- {
- /*对记录数组r[1...n]做归并排序*/
- MSort(r, 1, n, r);
- }
数据结构-排序算法总结与感悟相关推荐
- 数据结构---排序算法的总结
数据结构-排序算法的总结 分类 冒泡排序,时间复杂度O(n x n),空间复杂度O(1),稳定 简单选择排序,时间复杂度O(n x n),空间复杂度O(1),不稳定 希尔排序,时间复杂度O(n^1.3 ...
- 【数据结构排序算法系列】数据结构八大排序算法
排序算法在计算机应用中随处可见,如Windows操作系统的文件管理中会自动对用户创建的文件按照一定的规则排序(这个规则用户可以自定义,默认按照文件名排序)因此熟练掌握各种排序算法是非常重要的,本博客将 ...
- C++基础-介绍·数据结构·排序·算法
C++基础-介绍·数据结构·排序·算法 特点 使用方向 RPC Data Struct 数据结构 栈 Stack 内存分配中的栈 队列 List 数组 Array 链表 LinkTable 树 Tre ...
- 数据结构-排序算法(c语言实现篇)
数据结构-排序算法(c语言实现篇) 排序算法是非常常用的算法,从介绍排序的基本概念,到介绍各种排序算法的思想.实现方式以及效率分析.最后比较各种算法的优劣性和稳定性. 1 排序的概念及应用 1.1 排 ...
- 数据结构排序算法实验报告_数据结构与算法-堆排序
堆排序 堆排序是指利用堆这种数据结构所设计的一种排序算法.堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子节点的键值或索引总是小于(或者大于)它的父节点,堆排序的时间复杂度为O(nlogn).( ...
- 选择排序稳定吗_最常见的四种数据结构排序算法你不知道?年末怎么跳槽涨薪...
前言 在学习数据结构的时候必然接触过排序算法,而且在日常开发中相信排序算法用得也比较多.而排序算法众多,各个效率又不同,难以记住.小编今天会介绍一些常用排序算法的特点和实现,对比不同排序算法的效率. ...
- 数据结构排序算法实验报告_[数据结构与算法系列]排序算法(二)
我的上一篇文章向大家介绍了排序算法中的冒泡排序.插入排序和选择排序.它们都是平均时间复杂度为 O(n^2) 的排序算法,同时还为大家讲解了什么是原地排序和什么是排序的稳定性.下图是这三种算法的比较,不 ...
- 数据结构——排序算法(含动态图片)
目录 插入排序 交换排序 选择排序 归并排序 常用排序算法复杂度和稳定性总结 前言 排序是<数据结构>中最基本的学习内容.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行 ...
- 数据结构—排序算法总结(插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、合并排序、计数排序)
*排序 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性 在待排序的数组中,如果出现多个相同的关键字,例如:98751555512,中出现重复的数字,在 ...
最新文章
- 04flex弹性布局子项常见属性总结
- C#操作SharePoint列表
- how to debug Opportunity change implementation - entry onOKParticipantDialog
- Cheat_Sheet ---Keras、Matlab、Matplotlib、Numpy、Pandas、Scikit-Learn、SciPy
- 为爱追寻_从机械师到编码员:追寻梦想如何改变了我的生活
- JAVA笔记-Oracle中存储过程编写类似于MySQL的replace功能
- 【bzoj3329】Xorequ 数位dp+矩阵乘法
- wt在matlab中什么意思,new wt.是什么意思
- 《Spring Cloud Netflix》 -- 服务注册和服务发现-Eureka的常用配置
- RRC 常用名词解释
- jdk版本导致的DB2异常:必需的字符转换器不可用。ERRORCODE=-4220, SQLSTATE=null
- YYtext简单使用
- 010 Editor 9.x.x——安装、注册和汉化
- 浏览器播放视频时蓝牙耳机自动关机
- 数字货币智能合约的概念与演变
- 清华大学计算机科学与技术系朱军教授:机器学习里的贝叶斯基本理论、模型和算法...
- GitBook运行报错 - Error: ENOENT: no such file or directory, stat
- postman预处理/前置条件Pre-request
- GLSL——绘制平面图形(一)
- 不联网也传染!新型病毒通过USB无线传输传播
热门文章
- Android模拟器横屏和竖屏的切换
- 南阳理工学院计算机科学与技术分数线,2017南阳理工计算机科学与技术分数
- 宏基因组理论教程1宏基因组简介
- 股票的大底部形态,常见几种底部形态详解
- rtx a1000相当于什么显卡 rtxa1000相当于gtx多
- 删除导航窗格多余的图标,如Onedrive、3D对象
- pip install -U里面的-U是什么意思
- 腾讯云CDN2023年1月5日起,将按用户访问的 HTTPS 请求数次数单独计费,对我有影响吗?
- Origin2018(汉化版)在使用科学计数法的时候如何将坐标刻度的0.0改成0
- VisionPro脚本详解