八大常见内排序java实现
虽然排序算法烂大街了,但是哥依然用java实现了一遍,只为自己练练手,后面可以时不时的回头看看。。。仅此而已,各位可以提意见,莫喷!!
一、冒泡排序
基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换
/**
* 冒泡排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, boolean reverse) {
if (data.length == 1) {
return;
}
for (int i = 0; i < data.length - 1; i++) {
int tmp = 0;
for (int j = 0; j < data.length - i - 1; j++) {
if (reverse) { //从小到大(ture)
if (data[j] >= data[j+1]) {
tmp = data[j];
data[j] = data[j +1 ];
data[j+1] = tmp;
}
} else { //从大到小(false)
if (data[j] <= data[j+1]) {
tmp = data[j+1];
data[j+1] = data[j];
data[j] = tmp;
}
}
}
}
}
二、堆排序
基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。
堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,...,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数
/**
* 堆排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, boolean reverse) {
if (data.length == 1) {
return;
}
for (int i = 0; i < data.length; i++) {
//建堆
buildHeap(data, 0, data.length -1 - i, reverse);
int tmp = data[0];
data[0] = data[data.length - 1 - i];
data[data.length - 1 - i] = tmp;
}
} /**
* 将指定开始和结束段的数据建堆
* @param data
* @param beginIndex
* @param endIndex
* @param reverse
*/
public static void buildHeap(int[] data, int beginIndex, int endIndex, boolean reverse) {
if (beginIndex >= endIndex) {
return;
}
for (int i = (endIndex + beginIndex - 1) / 2; i >= beginIndex; i--) {
int cur = i;
if (reverse) { //大顶堆,用来从小到大排序
//发生交换之后需要检查孙子节点,重孙子节点...
while (2 * cur + 1 <= endIndex) {
int biggerChildIndex = 2 * cur + 1;
if (biggerChildIndex + 1 <= endIndex) {
if (data[biggerChildIndex] < data[biggerChildIndex + 1]) {
biggerChildIndex = biggerChildIndex + 1;
}
}
//找到最大子节点,如果比当前节点大,就交换
if (data[i] < data[biggerChildIndex]) {
int tmp = data[i];
data[i] = data[biggerChildIndex];
data[biggerChildIndex] = tmp;
//准备检查孙子节点
cur = biggerChildIndex;
} else {
break;
}
}
} else { //小顶堆,用来从大到小排序
//发生交换之后需要检查孙子节点,重孙子节点...
while (2 * cur + 1 <= endIndex) {
int samllerChildIndex = 2 * i + 1;
if (samllerChildIndex + 1 <= endIndex) {
if (data[samllerChildIndex] > data[samllerChildIndex + 1]) {
samllerChildIndex = samllerChildIndex + 1;
}
}
//找到最小子节点,如果比当前节点小,就交换
if (data[i] > data[samllerChildIndex]) {
int tmp = data[i];
data[i] = data[samllerChildIndex];
data[samllerChildIndex] = tmp;
cur = samllerChildIndex;
} else {
break;
}
}
}
}
}
三、直接插入排序
基本思想:在要排序的一组数中,假设前面(n-1)[n>=2]个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
/**
* 插入排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, boolean reverse) {
if (data.length == 1) {
return;
}
int tmp = 0;
for (int i = 1; i < data.length; i++) {
tmp = data[i];
int n = i - 1;
for (; n >= 0; n--) {
if (reverse) { //从小到大排序
if (data[n] >= tmp) {
data[n + 1] = data[n]; //将大于当前值的数后移一个位置
} else {
break;
}
} else { //从大到小排序
if (data[n] <= tmp) {
data[n + 1] = data[n]; //将小于当前值的数后移一个位置
} else {
break;
}
}
}
data[n+1] = tmp;
}
}
四、归并排序
基本思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
/**
* 归并排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, int left, int right, boolean reverse) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
sort(data, left, mid, reverse);
sort(data, mid + 1, right, reverse);
merge(data, left, mid, right, reverse);
} /**
* 合并已排序好的两段
* @param data
* @param left
* @param mid
* @param right
* @param reverse
*/
public static void merge(int[] data, int left, int mid, int right, boolean reverse) {
int[] tmp = new int[right - left + 1];
int i = left;
int j = mid + 1;
int n = 0;
while (i <= mid && j <= right) {
if (reverse) { //从小到大
if (data[i] <= data[j]) {
tmp[n++] = data[i++];
} else {
tmp[n++] = data[j++];
}
} else { //从大到小
if (data[i] <= data[j]) {
tmp[n++] = data[j++];
} else {
tmp[n++] = data[i++];
}
}
}
while (i <= mid) {
tmp[n++] = data[i++];
}
while (j <= right) {
tmp[n++] = data[j++];
}
for (int k = 0; k < tmp.length; k++) {
data[left + k] = tmp[k];
}
}
五、快递排序
基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分
/**
* 快速排序
* @param data
* @param left
* @param right
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, int left, int right, boolean reverse) {
if (left >= right) {
return;
}
int index = getIndex(data, left, right, reverse);
sort(data, left, index - 1, reverse);
sort(data, index + 1, right, reverse);
} /**
* 将待排序片段调整顺序,获得"中间数据"的正确索引
* @param data
* @param left
* @param right
* @param reverse 从大到小(false)还是从小到大(ture)
* @return
*/
public static int getIndex(int[] data, int left, int right, boolean reverse) {
int cur = data[left];
int i = left;
int j = right;
while (i < j) {
if (reverse) { //从小到大
while (data[j] > cur && i < j) {
--j;
}
data[i] = data[j];
while (data[i] <= cur && i < j) {
++i;
}
data[j]=data[i];
} else { //从大到小
while (data[j] < cur && i < j) {
--j;
}
data[i]=data[j];
while (data[i] >= cur && i < j) {
++i;
}
data[j]=data[i];
}
}
data[i] = cur;
return i;
}
六、基数排序
基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
/**
* 基数排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, boolean reverse) {
if (data.length == 1) {
return;
}
int max = 0;
for (int i = 0; i < data.length; i++) { //找出最大的数据
if (max < data[i]) {
max = data[i];
}
}
System.out.println("the max number is :" + max);
int radix = 1;
ArrayList<ArrayList<Integer>> numbers = new ArrayList<ArrayList<Integer>>(10);
for (int i = 0; i < 10; i++) {
numbers.add(i, new ArrayList<Integer>());
}
while (max > radix) {
for (int i = 0; i < data.length; i++) {
int index = (data[i] / radix) % 10;
ArrayList<Integer> list = numbers.get(index);
list.add(data[i]);
numbers.set(index, list);
}
resetOrder(data, numbers, reverse);
radix = radix * 10;
}
} /**
* 重新调整数组顺序
* @param data
* @param numbers
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void resetOrder(int[] data, ArrayList<ArrayList<Integer>> numbers, boolean reverse) {
int n = 0;
if (reverse) {
for (int i = 0; i < numbers.size(); i++) {
ArrayList<Integer> list = numbers.get(i);
while(list.size()>0){
data[n++] = list.get(0);
list.remove(0);
}
}
} else {
for (int i = numbers.size() - 1; i >= 0; i--) {
ArrayList<Integer> list = numbers.get(i);
while(list.size()>0){
data[n++] = list.get(0);
list.remove(0);
}
}
}
}
七、选择排序
基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
/**
* 选择排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, boolean reverse) {
if (data.length == 1) {
return;
}
for(int i=0;i<data.length-1;i++){
int tmp=data[i]; //要初始化
int index = i; //要初始化
for(int j=i;j<data.length;j++){
if(reverse) { //从小到大(ture)
if (tmp>=data[j]){
tmp = data[j]; //最小值
index = j;
}
}else {
if (tmp<=data[j]){
tmp = data[j]; //最大值
index = j;
}
}
}
data[index] = data[i];
data[i] = tmp;
}
}
八、希尔排序
基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。
/**
* 希尔排序
* @param data 要排序的数组
* @param reverse 从大到小(false)还是从小到大(ture)
*/
public static void sort(int[] data, boolean reverse) {
if (data.length == 1) {
return;
}
for (int d = data.length / 2; d >= 1; d = d / 2) { //组大小
for (int k = 0; k < d; k++) { //多少组
for (int n = d + k; n < data.length; n = n + d) { //同一组
int cur = n;
while (cur - d >= 0) { //插入排序
int tmp = 0;
if (reverse) { //小到大(ture)
if (data[cur] <= data[cur - d]) {
tmp = data[cur];
data[cur] = data[cur - d];
data[cur - d] = tmp;
}
} else { //从大到小(false)
if (data[cur] >= data[cur - d]) {
tmp = data[cur];
data[cur] = data[cur - d];
data[cur - d] = tmp;
}
}
cur = cur - d;
}
}
}
} }
相关的资料大伙可以自行寻找,本文就不详细介绍了。。。 都烂大街了。。。
以下是一些不错的相关文章
参考:
1.http://blog.csdn.net/qy1387/article/details/7752973#0-tsina-1-35851-397232819ff9a47a7b7e80a40613cfe1
2.http://www.cnblogs.com/luxiaoxun/archive/2012/09/01/2666677.html
3.http://www.cnblogs.com/yefengmeander/archive/2008/12/05/2887903.html
4.http://blog.jobbole.com/79288/
5.https://github.com/ztgu/sorting_algorithms_py
就当自己回顾知识了
八大常见内排序java实现的更多相关文章
- 一些常见的Java面试题 & 面试感悟
< 前言 > 近期在面试,深感这个行业的浮躁,一些菜不辣基的弱鸡开出的工资待遇要求,超过了我.不知道他们是怎么拿到那么高的工资的,难道是他在公司有亲戚朋友吗?有后台吗?是行业热钱真的过多了 ...
- 200个最常见的JAVA面试问题(附答案)
本文内容: 20个最常见的JAVA面试问题(附答案) 13个单例模式JAVA面试问题(附答案) 说说JVM和垃圾收集是如何工作的(附答案) 说说如何避免JAVA线程死锁(附答案) Java中HashS ...
- 最常见的Java面试题及答案汇总(三)
上一篇:最常见的Java面试题及答案汇总(二) 多线程 35. 并行和并发有什么区别? 并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔发生. 并行是在不同实体上的多个事 ...
- 最常见的Java面试题及答案汇总(二)
上一篇:最常见的Java面试题及答案汇总(一) 容器 18. java 容器都有哪些? 常用容器的图录: 19. Collection 和 Collections 有什么区别? java.util.C ...
- Java 实现常见内排序
一.内排序 1.排序基本概念 (1)什么是排序? 排序指将一个数据元素集合或者序列 按照某种规则 重新排列成一个 有序的集合或者序列.分为内排序.外排序.排序算法的好坏直接影响程序的执行速度以及存储空 ...
- 八大排序算法Java
目录(?)[-] 概述 插入排序直接插入排序Straight Insertion Sort 插入排序希尔排序Shells Sort 选择排序简单选择排序Simple Selection Sort 选择 ...
- 八大排序算法Java实现
本文对常见的排序算法进行了总结. 常见排序算法如下: 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 它们都属于内部排序,也就是只考虑数据量较小仅需要使用内存的排 ...
- 常见的java 错误--转
Java常见错误列表: 找不到符号(symbol) 类X是public的,应该被声明在名为X.java的文件中 缺失类.接口或枚举类型 缺失X 缺失标识符 非法的表达式开头 类型不兼容 非法的方法声明 ...
- 常见的Java面试题整理
面试是我们每个人都要经历的事情,大部分人且不止一次,这里给大家总结常见的面试题,让大家在找工作时候能够事半功倍. 1 Switch能否用string做参数? a.在 Java 7 之前, switch ...
随机推荐
- error C3872: "0xa0": 此字符不允许在标识符中使用
整理:这是因为直接复制代码的问题.0xa0是十六进制数,换成十进制就是160,表示汉字的开始. 解决办法:在报错的代码行检查两边的空格,用英文输入法的空格替换掉. 万恶的网络,万恶的word,这些无厘 ...
- Logparser 的用法
Logparser是一款非常强大的日志分析软件,可以帮助你详细的分析网站日志.是所有数据分析和网站优化人员都应该会的一个软件.Logparser是微软的一款软件完全免费的,大家可以在微软的官网上去下载 ...
- Asp.Net的两种开发方式
来源:http://www.zhidao91.com/asp-net/ 在经过对.Net平台深入的学习以后,我发现很多语言开发动态网站时,它的后台逻辑都差不多是相同的,今天在这里我给大家来聊聊在.Ne ...
- JavaScript实例-----反选
<!DOCTYPE HTML> <html> <head> <script> function myFunction() { var oTab = do ...
- Github上Python开发者应该关心的Repo
carbaugh/lice lice : Generate license files for your projects 一个用来为你的项目生成许可证的工具.这下可方便了,不用手工的去修改了! co ...
- #Linux学习笔记# 自定义shell终端提示符
我使用的Linux发行版是LinuxMint 17.2 Rafaela,默认情况下Terminal中的shell提示包括了用户名.主机名.当前目录(绝对路径)和提示符.这样会导致当进入一个比较深的目录 ...
- 每天一个linux命令(25):df 命令
linux中df命令的功能是用来检查linux服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 1.命令格式: df [选项] [文件] 2.命 ...
- php Curl_setop 的学习
cur_op的学习 ###curl_setopt (int ch, string option, mixed value) option的参数 CURLOPT_INFILESIZE: 当你上传一个文件 ...
- SQL基础知识总结(一)
1.union 和union all 操作符 1)union内部的select语句必须拥有相同的列,列也必须有相似的数字类型.同时,每条select语句中列的顺序相同. union语法(结果集无重复) ...
- .net架构设计读书笔记--第三章 第9节 域模型实现(ImplementingDomain Model)
我们长时间争论什么方案是实现域业务领域层架构的最佳方法.最后,我们用一个在线商店案例来说明,其中忽略了许多之前遇到的一些场景.在线商店对很多人来说更容易理解. 一.在线商店项目简介 1. 用例 ...