数据结构与算法(C/C++版)【排序】
第八章《排序》
一、直接插入排序
//直接插入排序
//算法思想:每趟将一个待排的关键字按照其值的大小插入到已经排好的部分有序序列的适当位置上,直到所有待排关键字都被插入到有序序列中为止。
//(1)时间复杂度分析:
// ①最坏情况(整个序列逆序):O(n²)
// ②最好情况(整个序列有序):O(n)
// ③平均时间复杂度:O(n²)
//(2)空间复杂度分析:
// ①:O(1)
void InsertSort(int R[], int n) //待排关键字存储在R[]中,默认为整型,个数为n
{
int i,j;
int temp;
for(int i= ; i<n; i++) //无序列表中挑选元素
{
temp=R[i]; //将带插入关键字暂存于temp中
j=i-;
while(j> && temp < R[j]) //循环完成从待排关键字之前的关键字开始扫描,如果大于待排关键字,则后移一位
{
R[j+] = R[j];
--j;
}
R[j+] = temp; //将temp中暂存的待排关键字插入到正确位置
}
}
二、折半插入排序
//折半插入排序
//算法思想:数据本身有序的前提下,取数据中间的元素与待插入元素进行对比,若待插入元素大于中间元素,则右半部分重复相同查找插入操作;若待插入元素小于中间元素,则左半部分重复相同查找插入操作;以此类推,直到插入待插入元素。
//(1)时间复杂度分析:
// ①最坏情况(整个序列逆序):O(n²)
// ②最好情况(整个序列有序):O(nlog₂n)
// ③平均时间复杂度:O(n²)
//(2)空间复杂度分析:
// ①:O(1)
void BInsertSort(int a[],int size)
{
int i,j,low = ,high = ,mid;
int temp = ;
for (i=; i<size; i++)
{
low=;
high=i-;
temp=a[i];
//采用折半查找法判断插入位置,最终变量 low 表示插入位置
while (low<=high)
{
mid=(low+high)/;
if (a[mid]>temp)
{
high=mid-;
}
else
{
low=mid+;
}
}
//有序表中插入位置后的元素统一后移
for (j=i; j>low; j--)
{
a[j]=a[j-];
}
a[low]=temp;//插入元素
}
}
三、希尔排序
//希尔排序
//算法思想:以增量来分割整个序列,将分割的各组进行直接插入排序,然后继续相同操作直到最后以增量1分割整个序列,其实就是对整个序列进行一趟直接插入排序,从而完成整个希尔排序。
//(1)时间复杂度分析:与增量的选取有关
// ①希尔自己提出的(每次除以2,并向下取整):O(n²)
// ②2^k+1,且小于待排序列长度:O(n^1.5)
// ③选取增量需注意:1.增量序列的最后一个值一定取1
// 2.增量序列中的值应尽量没有除1之外的公因子
//(2)空间复杂度分析:
// ①:O(1)
viod shellSort(int arr[],int n)
{
int temp;
for(int gap=n/;gap>;gap/=)
{
for(int i=gap;i<n;++i)
{
temp=arr[i];
int j;
for(j=i;j>=gap && arr[j-gap]>temp;j-=gap) //每个元素与自己组内的数据进行直接插入排序
arr[j]=arr[j-gap];
arr[j]=temp;
}
}
}
四、冒泡排序
//冒泡排序
//算法思想:【把数据降序】第一个元素和第二个元素比较,若果第一个大则二者交换,否则不交换;然后第二个元素和第三个元素比较。。。。以此类推,最终最大的元素被换到了最后面,完成一趟冒泡排序,经过多躺这样的排序,最终整个序列完成降序操作。
//结束标志是:一趟排序过程中没有发生元素交换。
//(1)时间复杂度分析:
// ①最坏情况(整个序列逆序):O(n²)
// ②最好情况(整个序列有序):O(n)
// ③平均时间复杂度:O(n²)
//(2)空间复杂度分析:
// ①:O(1) void BubbleSort(int R[],int n) //默认待排序元素为整型
{
int i,j;
int flag;
int temp;
for(i=n-;i>=;--i) //无序序列范围(逐渐较少)
{
flag=; //变量flag用来标记本趟排序是否放生了交换
for(j=;j<=i;++j) //交换。若为0,前面没有元素,无意义
if(R[j-]>R[j])
{
temp=R[j];
R[j]=R[j-];
R[j-]=temp;
flag=;
}
if(flag==)
return;
}
}
五、快速排序
//快速排序
//算法思想:①取第一个元素P(此时留下一个空位),先从右往左找比P元素的小的元素,找到后把该元素放到左边的空位(此时右边留下一个空位),然后在从左往右找比P元素大的元素,找到后把该元素放到右边的空位(此时左边又留下一个空位),以此类推,使元素p归位;
// ②列表被p分成两部分,左边都比p小,右边都比p大;
// ③P两侧用同样的方式递归完成最终的排序。 //(1)时间复杂度分析:
// ①最坏情况(整个序列逆序):O(n²)
// ②最好情况(整个序列有序):O(nlog2₂n)
// ③平均时间复杂度:O(nlog2₂n)
//(2)空间复杂度分析:
// ①:O(log2₂n):递归需要栈的辅助 viod QuickSort(int R[],int low,int high) //对从R[low]到R[high]的元素进行排序
{
int temp;
int i=low,j=high;
if(low<high)
{
temp=R[low];
while(i!=j) //循环完成一趟排序,即将数组中小于temp的元素放在左边,大于temp的元素放在右边
{
while(j>i && R[j]>temp) //从右往左扫描,找到一个小于temp的元素
j--;
if(i<j)
{
R[i]=R[j]; //放在temp的左边
++i; //i右移一位
}
while(i<j && R[i]<temp) //从左往右扫描,找到一个大于temp的元素
++i;
if(<j)
{
R[j]=R[i]; //放在temp的右边
--j; //j右移一位
}
}
R[i]temp; //将temp放在最终位置
QuickSort(R,low,i-); //递归的对temp左边的元素进行排序
QuickSort(R,i+,high); //递归的对temp右边的元素进行排序
}
}
六、简单选择排序
//简单选择排序
//算法思想:从头到尾顺序扫描序列,找出一个最小的元素和第一个元素进行交换,接着从剩下的元素中继续这种选择和交换,最终使序列有序。
//(1)时间复杂度分析:
// ①:O(n²)
//(2)空间复杂度分析:
// ①:O(1):辅助存储空间不随待排序列规模的变化而变化,是个常量。 viod SelectSort(int R[],int n)
{
int i,j,k;
int temp;
for(i=;i<n;++i)
{
k=i;
for(j=i+;j<n;++j) //该循环从无序序列中挑选出一个最小的元素
if(R[k]>R[j])
k=j;
/* 下面3句完成最小元素与无序序列第一个元素的交换 */
temp=R[i];
R[i]=R[k];
R[k]=temp;
}
}
七、堆排序
//堆排序
//算法思想:
//(1)时间复杂度分析:
// ①:O(nlog2₂n)
//(2)空间复杂度分析:
// ①:O(1):辅助存储空间不随待排序列规模的变化而变化,是个常量。 /* 本函数完成在数组R[low]到R[high]范围内,对在位置low上的结点进行调整 */
void Sift(int R[],int low,int high) //R[]中是一棵完全二叉树,所以元素的存储必须从1开始
{
int i=low,j=*i; //R[j]是R[i]的左孩子结点
int temp=R[i];
while(j<=high)
{
if(j<high && R[j]<R[j+]) //若右孩子较大,则把j指向右孩子
++j; //j变为2*i+1
if(temp<R[j])
{
R[i]=R[j]; //将R[j]调整到双亲结点的位置上
i=j; //修改i和j的值,以便继续向下调整
j=*i;
}
else
break; //调整结束
}
R[i]=temp; //被调整结点的中放入最终位置
} /* 堆排序函数 */
viod heapSort(int R[],int n)
{
int i;
int temp;
for(i=n/;i>=;--i) //建立初始堆
Sift(R,i,n);
for(i=n;i>=;--i) //进行n-1次循环,完成堆排序
{
/* 以下3句换出了根结点中的元素,将其放入最终位置 */
temp=R[];
R[]=R[i];
R[i]=temp;
Sift(R,,i-); //在减少了1个元素的无序序列中进行调整
}
}
八、归并排序
//归并排序
//算法思想:
//(1)时间复杂度分析:
// ①:O(nlog2₂n)
//(2)空间复杂度分析:
// ①:O(1):辅助存储空间不随待排序列规模的变化而变化,是个常量。 void merge(int arr[],int low,int mid,int high)
{
int i,j,k;
int n1=mid -low+;
int n2=high-mid;
int L[n1],R[n2];
for(i=;i<n1;i++)
L[i]=arr[low+i];
for(j=;j<n2;j++)
R[j]=arr[mid++j];
i=;
j=;
k=low;
while(i<n1 && j<n2)
{
if(L[i]<=R[j])
arr[k]=L[i++];
else
arr[k]=R[j++];
k++;
}
while(i<n1)
arr[k++]=L[i++];
while(j<n2)
arr[k++]=R[j++];
} void mergeSort(int arr[],int low,int mid,int high)
{
if(low<high)
{
int mid=(low+high)/;
mergeSort(arr,low,mid); //归并排序前半段
mergeSort(a,mid+,high); //归并排序后半段
merge(A,low,mid,high); //merge()函数:把A数组中low到mid和mid+1到high范围内的两段有序序列归并成一段有序序列
}
}
总结对比
快速排序、归并排序 、堆排序三种排序算法的时间复杂度都是O(nlogn)
一般情况下,就运行时间而言:快速排序 < 归并排序 < 堆排序
三种排序算法的缺点:
①快速排序:极端情况下排序效率低
②归并排序:需要额外的内存开销
③堆排序:在快的排序算法中相对较慢
数据结构与算法(C/C++版)【排序】的更多相关文章
- 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈
定场诗 金山竹影几千秋,云索高飞水自流: 万里长江飘玉带,一轮银月滚金球. 远自湖北三千里,近到江南十六州: 美景一时观不透,天缘有分画中游. 前言 本章是重读<学习JavaScript数据结构 ...
- 重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列
定场诗 马瘦毛长蹄子肥,儿子偷爹不算贼,瞎大爷娶个瞎大奶奶,老两口过了多半辈,谁也没看见谁! 前言 本章为重读<学习JavaScript数据结构与算法-第三版>的系列文章,主要讲述队列数据 ...
- 数据结构和算法(Golang实现)(25)排序算法-快速排序
快速排序 快速排序是一种分治策略的排序算法,是由英国计算机科学家Tony Hoare发明的, 该算法被发布在1961年的Communications of the ACM 国际计算机学会月刊. 注:A ...
- 数据结构和算法(Golang实现)(18)排序算法-前言
排序算法 人类的发展中,我们学会了计数,比如知道小明今天打猎的兔子的数量是多少.另外一方面,我们也需要判断,今天哪个人打猎打得多,我们需要比较. 所以,排序这个很自然的需求就出来了.比如小明打了5只兔 ...
- 数据结构和算法(Golang实现)(19)排序算法-冒泡排序
冒泡排序 冒泡排序是大多数人学的第一种排序算法,在面试中,也是问的最多的一种,有时候还要求手写排序代码,因为比较简单. 冒泡排序属于交换类的排序算法. 一.算法介绍 现在有一堆乱序的数,比如:5 9 ...
- 数据结构和算法(Golang实现)(20)排序算法-选择排序
选择排序 选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次.虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟 ...
- 数据结构和算法(Golang实现)(21)排序算法-插入排序
插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...
- 数据结构和算法(Golang实现)(22)排序算法-希尔排序
希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...
- 数据结构和算法(Golang实现)(23)排序算法-归并排序
归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...
- 数据结构和算法(Golang实现)(24)排序算法-优先队列及堆排序
优先队列及堆排序 堆排序(Heap Sort)由威尔士-加拿大计算机科学家J. W. J. Williams在1964年发明,它利用了二叉堆(A binary heap)的性质实现了排序,并证明了二叉 ...
随机推荐
- 利用ShardingSphere-JDBC实现分库分表--配置中心的实现
在之前的文章中我详细描述了如何利用ShardingSphere-JDBC进行分库分表,同时也实现了简单的精确分库算法接口,详情见下面的链接: 利用ShardingSphere-JDBC实现分库分表 但 ...
- Leetcode之二分法专题-287. 寻找重复数(Find the Duplicate Number)
Leetcode之二分法专题-287. 寻找重复数(Find the Duplicate Number) 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 ...
- Oralce 触发器
今天做了一个需要用到触发器实现的功能中间去到了各种问题,还好最后都解决了: 整个过程中真是遇到了不少错误: ORA-04091: 表 KPGO.T_ISSUER 发生了变化, 触发器/函数不能读它 O ...
- 成功项目管理与PMP认证2017
http://study.163.com/course/courseLearn.htm?courseId=1064005#/learn/video?lessonId=1003778171&co ...
- 提示:unresolved import: PIL
解决方法: 1.打开Window>Preferences>PyDev>Interpreters>Python Interpreter>Forced Builtins,点击 ...
- SDU暑期集训排位(5)
SDU暑期集训排位(5) A. You're in the Army Now 题意 类似选志愿.每个人有 mark,有优先级从高到低的志愿. 做法 定睛一看,鲨鼻题.然后 WA. 为什么会 WA 呢? ...
- 最短路 dijkstra+优先队列+邻接表
http://acm.hdu.edu.cn/showproblem.php?pid=2544 #include<iostream> #include<queue> #inclu ...
- CodeForces 340E Iahub and Permutations 错排dp
Iahub and Permutations 题解: 令 cnt1 为可以没有限制位的填充数字个数. 令 cnt2 为有限制位的填充数字个数. 那么:对于cnt1来说, 他的值是cnt1! 然后我们对 ...
- POJ-2236 Wireless Network 顺便讨论时间超限问题
Wireless Network Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 26131 Accepted: 108 ...
- 用lnmp架构部署wordpress网站详细步骤
用lnmp架构部署wordpress网站 ①.下载和上传网站代码 用winscp或者xftp, 或者xshell下执行rz命令进行上传网站的包文件. ②.解压程序代码,并将程序代码保存到站点目录,并进 ...