第八章《排序》

 一、直接插入排序 

//直接插入排序
//算法思想:每趟将一个待排的关键字按照其值的大小插入到已经排好的部分有序序列的适当位置上,直到所有待排关键字都被插入到有序序列中为止。

//(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++版)【排序】的更多相关文章

  1. 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈

    定场诗 金山竹影几千秋,云索高飞水自流: 万里长江飘玉带,一轮银月滚金球. 远自湖北三千里,近到江南十六州: 美景一时观不透,天缘有分画中游. 前言 本章是重读<学习JavaScript数据结构 ...

  2. 重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列

    定场诗 马瘦毛长蹄子肥,儿子偷爹不算贼,瞎大爷娶个瞎大奶奶,老两口过了多半辈,谁也没看见谁! 前言 本章为重读<学习JavaScript数据结构与算法-第三版>的系列文章,主要讲述队列数据 ...

  3. 数据结构和算法(Golang实现)(25)排序算法-快速排序

    快速排序 快速排序是一种分治策略的排序算法,是由英国计算机科学家Tony Hoare发明的, 该算法被发布在1961年的Communications of the ACM 国际计算机学会月刊. 注:A ...

  4. 数据结构和算法(Golang实现)(18)排序算法-前言

    排序算法 人类的发展中,我们学会了计数,比如知道小明今天打猎的兔子的数量是多少.另外一方面,我们也需要判断,今天哪个人打猎打得多,我们需要比较. 所以,排序这个很自然的需求就出来了.比如小明打了5只兔 ...

  5. 数据结构和算法(Golang实现)(19)排序算法-冒泡排序

    冒泡排序 冒泡排序是大多数人学的第一种排序算法,在面试中,也是问的最多的一种,有时候还要求手写排序代码,因为比较简单. 冒泡排序属于交换类的排序算法. 一.算法介绍 现在有一堆乱序的数,比如:5 9 ...

  6. 数据结构和算法(Golang实现)(20)排序算法-选择排序

    选择排序 选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次.虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟 ...

  7. 数据结构和算法(Golang实现)(21)排序算法-插入排序

    插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...

  8. 数据结构和算法(Golang实现)(22)排序算法-希尔排序

    希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...

  9. 数据结构和算法(Golang实现)(23)排序算法-归并排序

    归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...

  10. 数据结构和算法(Golang实现)(24)排序算法-优先队列及堆排序

    优先队列及堆排序 堆排序(Heap Sort)由威尔士-加拿大计算机科学家J. W. J. Williams在1964年发明,它利用了二叉堆(A binary heap)的性质实现了排序,并证明了二叉 ...

随机推荐

  1. time_wait状态如何处理和建议

    TL;DR: do not enable net.ipv4.tcp_tw_recycle. UPDATED (2017.09): net.ipv4.tcp_tw_recycle has been re ...

  2. 剑指Offer(二十五):复杂链表的复制

    剑指Offer(二十五):复杂链表的复制 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/bai ...

  3. 骑士精神(IDA*)

    题目描述 输入格式 第一行有一个正整数T(T<=10),表示一共有N组数据.接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位.两组数据之间没有空行. 输出格式 对于每组数据都 ...

  4. 检查python标识符是否有效

  5. SPOJ - QTREE4 Query on a tree IV 边分治

    题目传送门 题意:有一棵数,每个节点有颜色,黑色或者白色,树边有边权,现在有2个操作,1修改某个点的颜色, 2询问2个白点的之前的路径权值最大和是多少. 题解: 边分治思路. 1.重构图. 因为边分治 ...

  6. 微信公众号之获取openId

    在小伙伴们开发微信公众号.小程序或者是在微信内置浏览器打开的项目时,会遇到的第一个问题就是如何获取openId,今天小编就给大家带来的是如何获取openId. 首先   我们要从微信开发者后台得到ap ...

  7. 【Nginx】实现负载均衡的几种方式

    要理解负载均衡,必须先搞清楚正向代理和反向代理. 注: 正向代理,代理的是用户. 反向代理,代理的是服务器 什么是负载均衡 当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能 ...

  8. R:ggplot2数据可视化——进阶(1)

    ,分为三个部分,此篇为Part1,推荐学习一些基础知识后阅读~ Part 1: Introduction to ggplot2, 覆盖构建简单图表并进行修饰的基础知识 Part 2: Customiz ...

  9. Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.catalina.connector.CoyoteWriter and no properties discovered to create BeanSerializer

    一.什么是序列化In computer science, in the context of data storage, serialization is the process of transla ...

  10. Python远程连接MySQL数据库

    使用Python连接数据库首先需要安装Python的数据库驱动. 我的本地只装了Python,并没有装MySQL,当我使用命令: sudo pip install mysql-python 安装驱动( ...