24.C语言最全排序方法小结(不断更新)
希尔排序:
该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。
由于直接插入排序在元素基本有序的情况下(接近最好情况),效率是非常高的,因此希尔排序在时间效率上比前两种方法有较大提高。
以n=10的一个数组49, 38, 65, 97, 26, 13, 27, 49, 55, 4为例
第一次 gap = 10 / 2 = 5
49 38 65 97 26 13 27 49 55 4
1A 1B
2A 2B
3A 3B
4A 4B
5A 5B
1A,1B,2A,2B等为分组标记,数字同样的表示在同一组,大写字母表示是该组的第几个元素, 每次对同一组的数据进行直接插入排序。
即分成了五组(49, 13) (38, 27) (65, 49) (97, 55) (26, 4)这样每组排序后就变成了(13, 49) (27, 38) (49, 65) (55, 97) (4, 26),下同。
第二次 gap = 5 / 2 = 2
排序后
13 27 49 55 4 49 38 65 97 26
1A 1B 1C 1D 1E
2A 2B 2C 2D 2E
第三次 gap = 2 / 2 = 1
4 26 13 27 38 49 49 55 97 65
1A 1B 1C 1D 1E 1F 1G 1H 1I 1J
第四次 gap = 1 / 2 = 0 排序完毕得到数组:
4 13 26 27 38 49 49 55 65 97
以下给出严格依照定义来写的希尔排序:
#include <stdio.h>
#include <stdlib.h> void show(int *p, int length)
{
for (int i = ; i < length; i++)
{
printf("%4d", p[i]);
}
printf("\n");
} void shellsort(int *p, int length)
{
int d = length / ;//增量
while (d >= )
{
//从后往前推
for (int i = d;d<length && i<length; i++)
{
int x = p[i];//备份当前数据
int j = i - d;//前面一个元素 //在数组范围内,找到插入的位置,如果大则把大的赋给后面,j一直是前一个位置
while (j >= && p[j] > x)
{
p[j + d] = p[j];
j = j - d;
}
//所以这里要加d
p[j + d] = x;
}
d /= ;//增量变化
}
} void main()
{
int a[] = { , , , , , , , , , };
show(a, );
shellsort(a, );
show(a, );
system("pause");
}
桶排序(基数排序)
桶排序(也称箱排序),据坊间演绎,其实现方式有很多。
在此我们仅仅阐述一下本文的实现思想,以便于更好的理解下面的内容,同时加深对桶排序的认识。
首先,说明一点,我们是使用数组模拟桶(最好应该是使用链表模拟)。
所谓数组模拟桶实现排序的过程到底是怎么进行的呢?呵呵!其实还真有点抽象。
实现步骤如下:
(1)定义映射函数
<1>求得欲排数据序列中的最大数据。
<2>通过遍历欲排数据对每个数据乘以10再与最大数据取余,求得每个数据对应桶的索引(或称关键字)。
(2)求得每个桶中盛放的数据个数(为了保证随后准确分配数据)
(3)求得每个桶盛放数据个数的右边界索引(所谓的桶逻辑控制)
(4)从右向左(确保稳定性)扫描欲排数据序列,依次分配到对应桶中
(5)对各桶中所盛数据进行收集
(6)利用插入排序再对各个桶中所盛数据进行排序
(7)直至排序结束,即为已排序数据序列
其实,整个过程再讲通俗一点,可以如下描述:
建立一个数组作为我们的所谓的桶(逻辑桶)
然后,申请开辟与欲排数据所占空间相同的内存,作为真正的盛放数据的桶(物理桶)
数组的索引默认为桶号
对数组的每一次赋值都有着不同的意义(请参考代码分析)
最后再用插入排序对各桶中所收集数据分别进行排序。即完成桶排序。
总而言之:先分类,后收集,再排序。
【2】示例代码及其分析过程
(1)代码如下:
#include<iostream>
#include<malloc.h>
using namespace std; void PrintArr(int ar[],int n)
{
for(int i = ; i < n; ++i)
cout<<ar[i]<<" ";
cout<<endl;
} int MapToIndex(int x,int max)
{
return ( * x) / max;
} void insertion_sort(int arr[],int begin,int end)
{
for(int i = begin+; i <= end; ++i)
{
int v = arr[i];
int j = i;
while(j- >= begin && v<arr[j-])
{
arr[j--] = arr[j-];
}
arr[j] = v;
}
} void bucket_sort(int ar[], int begin, int end)
{ const int radix = ; //注意:为什么是11?
int count[radix], i, j;
int size = end-begin+; //计数值置空
for(i = ; i < radix; ++i)
{
count[i] = ; //置空
} //end-begin+1 = 9 - 0 + 1 = 10
int *Temp = (int *) malloc((size) * sizeof(int)); //分配临时空间 //取得当前待排序数据中的最大数据
int max = ;
for(i = begin; i < size; ++i)
{
if(ar[i] > max)
max = ar[i];
} //统计各桶需要装的元素的个数
for(i = begin; i < size; ++i)
{
count[MapToIndex(ar[i], max)]++;
} //输出计数结果:
PrintArr(count, radix); //求出桶的边界索引,count[i]为第i个桶的右边界索引+1
for(i = ; i < radix; ++i)
{
count[i] = count[i] + count[i-];
} //输出桶边界索引
PrintArr(count, radix); //从右向左扫描,保证排序稳定性
for(i = end; i >= begin; --i)
{
j = MapToIndex(ar[i], max);
Temp[count[j]-] = ar[i]; //放入对应的空间中,count[j]-1是第j个桶的右边界索引
--count[j]; //准备放置下一个元素的位置索引
} for(int i = ; i < size; ++i)
{
cout<<Temp[i]<<" ";
}
cout<<endl; PrintArr(count, radix); //从各个桶中收集数据
for(i = begin, j = ; i < size; i++, j++)
{
ar[i] = Temp[j];
} PrintArr(ar, end+); //释放空间
free(Temp); for(i = ; i < size; i++)
{
int index1 = begin + count[i]; //得到第i个桶的左边界
int index2 = begin + count[i+] - ; //得到第i个桶的右边界
if(index1 < index2)
insertion_sort(ar, index1, index2);
}
} void main()
{
int ar[] = {, , , , , , , , , };
int len = sizeof(ar)/sizeof(int);
bucket_sort(ar, , len-);
PrintArr(ar, len);
}
/*
4 3 0 0 0 1 1 0 0 0 1
4 7 7 7 7 8 9 9 9 9 10
5 6 3 8 12 14 9 47 54 89
0 4 7 7 7 7 8 9 9 9 9
5 6 3 8 12 14 9 47 54 89
3 5 6 8 9 12 14 47 54 89
*/
(2)分析过程如下:
学过数据结构的估计都可以想象得到:桶排序中所谓的桶应该是用一个单链表实现
因为,我们一直觉得,计算机世界就是对现实世界的模拟。那么,既然是山寨,当然越逼真越好
但是,假如我们没有学习过单链表,脑子里面根本没有单链表的概念。而且,我们要实现桶排序。
好吧!我唯一可以借助的就是数组。
不过数组模拟桶实现桶排序的确不是很好理解,有几分抽象
上面这就是一个用数组模拟桶实现的桶排序示例代码,现在做一下具体分析,希望可以更深刻理解桶排序。
分析过程如下:
(1)待排序数据序列为:
(2)count数组本质上是逻辑的桶,为什么说是逻辑上的桶?因为,它控制着桶的所有数据逻辑
但是申请的内存Temp才是每个桶的真正储存空间,所以只能说是逻辑上的桶。
而当数据被分配到各个桶中又从桶(即就是从申请空间)被收集之后,就对申请空间进行释放(因为留着再没有必要)。
如何理解以上内容?请结合一下图示理解具体分析:
第一行:所建桶的索引(可以看到总共为11个桶)
为什么是11个桶?由我们在对待排数据求输入桶对应的索引时匹配函数(MapToIndex)决定。
由于最大数据输入匹配函数后所得桶对应索引为10。所以,在此必须如此设计。
第二行:所有桶置空
第三行:每个桶中待盛的数据个数
第四行:每个桶的右边界索引
如何理解右边界索引?
比如0号桶,第三行已经得出其待盛四个数据,那么将来数据就会存入Temp[0],Temp[1],Temp[2],Temp[3]
比如1号桶,第三行已经得出其待盛三个数据,那么将来数据就会存入Temp[4],Temp[5],Temp[6]
第五行:待排数据全部放入各个桶中后,桶的左边界索引(这个是为了下面插入排序使用)。
(3)对每一个桶(即就是申请空间)中所盛的数据再利用插入排序进行排序
(4)数组中的数据即为已排序序列
【3】桶排序分析
桶排序是稳定排序算法。
桶排序使用范围比较窄。
24.C语言最全排序方法小结(不断更新)的更多相关文章
- Python语言上机题实现方法(持续更新...)
Python语言上机题实现方法(持续更新...) 1.[字符串循环左移]给定一个字符串S,要求把S的前k个字符移动到S的尾部,如把字符串"abcdef"前面的2个字符'a'.'b' ...
- Linux中查看磁盘大小、文件大小、排序方法小结
一,查看磁盘空间大小的命令:dfdf命令用于查看磁盘分区上的磁盘空间,包括使用了多少,还剩多少,默认单位是KB 比如以下命令: df -hl执行结果如下: 执行的结果每列的含义: 第一列Filesys ...
- 【每日日报】第十八天 ----java最全排序方法
1 今天看了Java的第三章 2 冒泡法排序: package Line; import java.util.Arrays; public class MaoPao { public static v ...
- PCB 合拼遍历(全排序+旋转90度) 基本遍历方法
分享一下PCB合拼的组合的遍历方法,在分享之前先纠正一下 PCB拼板之多款矩形排样算法实现--学习 时间复杂度计算错误 一.PCB 合拼(全排序+旋转90度)的时间复杂度是多少? 二.合拼遍历(全 ...
- php语言实现的7种基本的排序方法
今天总结了一下常用的7种排序方法,并用php语言实现. 直接插入排序 /* * 直接插入排序,插入排序的思想是:当前插入位置之前的元素有序, * 若插入当前位置的元素比有序元素最后一个元素大,则什么也 ...
- Go语言中字符串的查找方法小结
这篇文章主要介绍了Go语言中字符串的查找方法小结,示例的main函数都是导入strings包然后使用其中的方法,需要的朋友可以参考下 1.func Contains(s, substr strin ...
- C语言中常见的排序方法
在C语言中,常见的排序方法有冒泡法,排序法,插入法等等.所谓的冒泡法,就是对一组数字进行从大到小或者从小到大的一种排序方法.主要就是相邻的数值相互交换.从第一个数值开始,如果这相邻的两个数值排序与我们 ...
- C语言 · 运用结构体的排序方法
之前遇到排序只想着最原始的方法,诸如冒泡,选择,快速排序等等,刚刚跟大牛学会了结构体的方法来排序,这样的话以后再也不用怕成绩统计.名次排序之类的题目了. 首先头文件(基于大牛的方法,本人之后做题喜欢引 ...
- javascript总结24:Array常用的队列操作和排序方法
1 数组-引用类型 JavaScript中的内置对象 复习数组的使用 两种创建数组的方式 Array对象的属性 length 获取数组的长度(元素个数) 2 常用方法 : 检测数组 instanceo ...
随机推荐
- BZOJ 1050 枚举+并查集
思路: 枚举最大边 像Kruskal一样加边 每回更新一下 就搞定了- //By SiriusRen #include <cstdio> #include <cstring> ...
- 利用Eventlog Analyzer分析日志
利用EventlogAnalyzer分析日志 ManageEngineEventLogAnalyzer是一个基于Web技术.实时的事件监控管理解决方案,能够提高企业网络安全.减少工作站和服务器的宕机事 ...
- [Chromium文档转载,第001章] Mojo Migration Guide
For Developers > Design Documents > Mojo > Mojo Migration Guide 目录 1 Summary 2 H ...
- BZOJ2690: 字符串游戏(平衡树动态维护Dfs序)
Description 给定N个仅有a~z组成的字符串ai,每个字符串都有一个权值vi,有M次操作,操作分三种: Cv x v':把第x个字符串的权值修改为v' Cs x a':把第x个字符串修改成a ...
- spring 使用c3po连接池
1 数据源:能够简单理解为数据的来源. 2 连接池:是缓存一定数量的数据库连接,当程序须要数据库连接的时候,直接在连接池中获取空暇的连接,使用完再放回连接池中,此连接又变成空暇状态,等待下一次连接. ...
- 百度地图ios环境配置
1 前言 由于工作需要,要开始捣腾百度地图了,今天上午初始牛刀,各种碰壁,无奈之下,中午睡了一觉,养精蓄锐,以备下午大战三百回合,所幸下午中午把百度地图Demo捣腾出来了,在此与大家分享,环境搭建教程 ...
- OpenCASCADE Extended Data Exchange - XDE
OpenCASCADE Extended Data Exchange - XDE eryar@163.com Abstract. OpenCASCADE Data Exchange allows de ...
- Android自己定义视图(一):带下划线的TextView
package com.francis.underlinetextviewtest; import android.content.Context; import android.content.re ...
- HTTP/2 服务器推送(Server Push)教程(HTTP/2 协议的主要目的是提高网页性能,配置Nginx和Apache)
HTTP/2 协议的主要目的是提高网页性能. 头信息(header)原来是直接传输文本,现在是压缩后传输.原来是同一个 TCP 连接里面,上一个回应(response)发送完了,服务器才能发送下一个, ...
- Thinkphp的 is null 查询条件是什么,以及exp表达式如何使用
Thinkphp的 is null 查询条件是什么,以及exp表达式如何使用 一.总结 一句话总结:$map['name'] = array('exp','is null'); 1.is null判断 ...