几种经典的数据排序及其Java实现
选择排序
思想
n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:
①初始状态:无序区为R[1..n],有序区为空。
②第1趟排序
在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
……
③第i趟排序
第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
排序实例
初始关键字 [49 38 65 97 76 13 27 49]
第一趟排序后 13 [38 65 97 76 49 27 49]
第二趟排序后 13 27 [65 97 76 49 38 49]
第三趟排序后 13 27 38 [97 76 49 65 49]
第四趟排序后 13 27 38 49 [76 97 65 49 ]
第五趟排序后 13 27 38 49 49 [97 65 76]
第六趟排序后 13 27 38 49 49 65 [97 76]
第七趟排序后 13 27 38 49 49 65 76 [97]
最后排序结果 13 27 38 49 49 65 76 97
Java实现代码如下:
package selectsort; public class Sort {
public static void main(String[] args)
{
int[] a = {8,77,66,99,2,7,4,6,100,34};
int[] b ;
b = selectsort(a);
for(int i = 0; i < b.length; i++)
{
System.out.println(b[i]);
}
}
public static int[] selectsort(int[] p)
{
int temp = 0;
int minindex = 0;
int[] array = p.clone();
for(int i = 0; i < array.length; i++)
{
minindex = i;
for(int j = i+1; j < array.length; j++)
{
if(array[minindex] > array[j] )
minindex = j;
}
temp = array[i];
array[i] = array[minindex];
array[minindex] = temp;
}
return array;
}
}
结果验证正确。
冒泡法
原理
冒泡排序算法的运作如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
算法分析
算法稳定性
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
Java实现代码:
package bubblesort; public class Bubblesort {
public static void main(String[] args)
{
int[] a = {8,77,66,99,2,7,4,6,100,34};
int[] b;
b = bubble(a);
for(int i =0; i <b.length; i++ )
{
System.out.println(b[i]);
} }
public static int[] bubble(int[] a)
{
int[] array = a.clone();
for(int i = 0; i < array.length - 1; i++)
{
for(int j = 0; j < array.length - 1 - i; j++)
{
if(array[j] > array[j+1])
sway(array,j,j+1);
}
}
return array;
}
public static void sway(int[] b, int m, int n)
{
int temp = b[m];
b[m] = b[n];
b[n] = temp;
} }
插入排序
插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
算法描述一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:从第一个元素开始,该元素可以认为已经被排序取出下一个元素,在已经排序的元素序列中从后向前扫描如果该元素(已排序)大于新元素,将该元素移到下一位置重复步骤3,直到找到已排序的元素小于或者等于新元素的位置将新元素插入到该位置后重复步骤2~5如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。
Java示例代码如下:
package insertsort; public class Insert {
public static void main(String[] args)
{
int[] a = {500,77,66,99,2,7,4,6,100,34};
int[] b;
b = insert(a);
for(int i =0; i <b.length; i++ )
{
System.out.println(b[i]);
}
}
public static int[] insert(int[] c)
{
int[] array = c.clone();
for(int i = 1; i < array.length; i++)
{
if(array[i] < array[i - 1])
{
int temp = array[i];
int j = i;
while((j>0)&&(array[j - 1] > temp))
{
array[j] = array[j - 1];
j--;
}
array[j] = temp;
}
}
return array;
}
}
希尔排序
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n2)的排序(冒泡排序或插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。
一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用i += step_size而不是i++)。
例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:
13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
然后我们对每列进行排序:
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
将上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:
10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
排序之后变为:
10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最后以1步长进行排序(此时就是简单的插入排序了)。
package shellsort; public class shellsort {
public static void main(String[] args)
{
int[] a = {500,77,66,99,2,7,4,6,100,34};
int[] b;
b = shell(a);
for(int i =0; i <b.length; i++ )
{
System.out.println(b[i]);
}
}
public static int[] shell(int[] a)
{
int[] array = a.clone();
int len = array.length;
int i = 0;
int j = 0;
int k = -1;
int temp = -1;
int gap = len; do
{
gap = gap / 3 + 1; for(i=gap; i<len; i+=gap)
{
k = i;
temp = array[k]; for(j=i-gap; (j>=0) && (array[j]>temp); j-=gap)
{
array[j+gap] = array[j];
k = j;
} array[k] = temp;
} }while( gap > 1 ); return array;
}
}
快速排序
算法步骤:假设待划分序列为r[left],r[left+1],.......r[right],具体实现上述划分过程时,可以设两个指针i和j,他们的初值分别为left,right.首先将基准记录r[left]移至变量x中,是r[left],即r[i]相当于空单元,然后反复进行如下两个扫描过程,直到i和j相遇
(1)j从右向左扫描,直到r[j].key<x.key时,将r[j]移至控单元r[i],此时r[j]相当于控单元。
(2)i从左向后扫描,直到r[i].key>x.key时,将r[i]移至空单元r[j],此时r[i]相当于空单元。
当i和j相遇时,r[i](或r[j])相当与空单元,且r[i]左边所有记录的关键字均不大于基准记录的关键字,而r[i]右边所有记录的关键字均不小于基准记录的关键字,最后将基准记录移至r[i]中,就完成了一次划分过程。最后对子表进行递归调用排序函数进行排序。
Java示例代码如下:
package quicksort; public class Quick {
public static void main(String[] args)
{
int[] a = {500,77,66,99,2,7,4,6,100,34,1000,888,777,666,555,333,222,111,87,45,69,12,45,}; QuickSort(a,a.length);
for(int i =0; i <a.length; i++ )
{
System.out.println(a[i]);
}
}
public static void swap(int[] array, int i, int j)
{
int temp = array[i]; array[i] = array[j]; array[j] = temp;
} public static int partition(int[] array, int low, int high)
{
int pv = array[low]; while( low < high )
{
while( (low < high) && (array[high] >= pv) )
{
high--;
} swap(array, low, high); while( (low < high) && (array[low] <= pv) )
{
low++;
} swap(array, low, high);
} return low;
} public static void QSort(int[] array, int low, int high)
{
if( low < high )
{
int pivot = partition(array, low, high); QSort(array, low, pivot-1);
QSort(array, pivot+1, high);
}
} public static void QuickSort(int[] array, int len) // O(n*logn)
{
QSort(array, 0, len-1);
} }
归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。值得注意的是归并排序是一种稳定的排序方法。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并操作
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;
算法描述
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
package MergeSortClass; public class MergeSortClass {
private int[] SortOut;
public void printSortedOutput()
{
for (int i = 0; i < this.SortOut.length; i++)
{
System.out.print(this.SortOut[i] + " ");
}
} public static void main(String[] args)
{
int[] in = { 2, 5, 3, 8, 6, 7, 1, 4, 0, 9 };
MergeSortClass msTest = new MergeSortClass(in);
msTest.printSortedOutput();
} public MergeSortClass(int[] in)
{
this.SortOut=this.MergeSort(in);
} private int[] MergeSort(int[] i_list)
{
if (i_list.length == 1) {
return i_list;
} else {
int[] listL = new int[i_list.length / 2];
int[] listR = new int[i_list.length - i_list.length / 2];
int Center = i_list.length / 2;
for (int i = 0; i < Center; i++) {
listL[i] = i_list[i];
}
for (int i = Center, j = 0; i < i_list.length; i++, j++) {
listR[j] = i_list[i];
} int[] SortedListL=MergeSort(listL);
int[] SortedListR=MergeSort(listR);
int[] o_list = MergeTwoList(SortedListL, SortedListR);
return o_list;
}
} private int[] MergeTwoList(int[] listL, int[] listR)
{
int i = 0, j = 0;
int[] o_list = new int[listL.length + listR.length];
int foot = 0;
while (i < listL.length && j < listR.length) {
if (listL[i] <= listR[j]) {
o_list[foot] = listL[i];
i++;
} else {
o_list[foot] = listR[j];
j++;
}
foot++;
} if (i == listL.length) {
while (j < listR.length) {
o_list[foot++] = listR[j++];
}
} else { // j==listR.length
while (i < listL.length) {
o_list[foot++] = listL[i++];
}
}
return o_list;
}
}
几种经典的数据排序及其Java实现的更多相关文章
- 七种经典排序算法及Java实现
排序算法稳定性表示两个值相同的元素在排序前后是否有位置变化.如果前后位置变化,则排序算法是不稳定的,否则是稳定的.稳定性的定义符合常理,两个值相同的元素无需再次交换位置,交换位置是做了一次无用功. 下 ...
- java学习-排序及加密签名时数据排序方式
排序有两种 1. 类实现comparable接口调用List.sort(null)或Collections.sort(List<T>)方法进行排序 jdk内置的基本类型包装类等都实现了Co ...
- 十大经典排序【Java实现,手工作坊式】
终于把排序这个硬骨头,但是又很基础的知识点,自己手撕了一遍!之前,使用Python看着算法导论的书手撕过一遍,印象不是很深刻,容易忘记!好记性不如烂笔头!多自己思考解决问题 1,交换类CAS[最简单] ...
- 基于python的七种经典排序算法
参考书目:<大话数据结构> 一.排序的基本概念和分类 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法. ...
- java中的排序(自定义数据排序)--使用Collections的sort方法
排序:将一组数据按相应的规则 排列 顺序 1.规则: 基本数据类型:日常的大小排序. 引用类型: 内置引用类型(String,Integer..),内部已经指定规则,直接使用即可.---- ...
- 基于python的七种经典排序算法(转)
一.排序的基本概念和分类 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法. 排序的稳定性:经过某种排序后,如果两个 ...
- 几种经典排序算法的R语言描述
1.数据准备 # 测试数组 vector = c(,,,,,,,,,,,,,,) vector ## [] 2.R语言内置排序函数 在R中和排序相关的函数主要有三个:sort(),rank(),ord ...
- 一种从JSON数据创建Java类的高效办法
<一种从JSON数据创建Java类的高效办法> 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs JSON格式的数据经常会遇到,比如调用Web服 ...
- Java案例——字符串中的数据排序
需求:有一个字符串"9 1 2 7 4 6 3 8 5 0",请编写程序实现从小到大数据排序 分析:最重要的部分是如何将字符串中的数据取出来 1.定义一个字符串为"9 1 ...
随机推荐
- HDU 2570:迷瘴
迷瘴 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...
- SVN基础命令手册
SVN版本号:1.5 及更新版本号 名词说明: WC:Working Copy 你的工作区 Versioned:受控的:受版本号控制的 SVN是什么? SVN是开源的版本号控制系统. 比CVS很多其它 ...
- STL之优先级队列priority_queue
摘要: priority_queue,自适应容器(即容器适配器):不能由list来组建: 最大值优先级队列(最大值始终在对首,push进去时候) 最小值优先级队列: 优先级队列适配器 STL pri ...
- C程序设计语言之一
%d 按照十进制整形数打印: %o 按照八进制整形数打印: %x 按照十六进制整形数打印: %c 表示字符 %s 表示字符串 %% 表示%本身打印: %ld long型输出 ”幻数“: #define ...
- MYSQL - php 使用 localhost 无法连接数据库
php 使用 localhost 无法连接数据库,而使用127.0.0.1却能连接成功. 可能原因: 系统hosts文件未提供127.0.0.1到localhost的解析.解决方法(以win7系统为例 ...
- javascript学习(10)——[知识储备]链式调用
上次我们简单的说了下单例的用法,这个也是在我们java中比较常见的设计模式. 今天简单说下链式调用,可能有很多人并没有听过链式调用,但是其实只要我简单的说下的话,你肯定基本上都在用,大家熟知的jQue ...
- [转] Chrome 控制台不完全指南
转自: http://www.cnblogs.com/Wayou/p/chrome-console-tips-and-tricks.html#home Chrome的开发者工具已经强大到没朋友的地步了 ...
- Android 开发 AirPlay Server
安卓上开发 AirPlay Server 主要是参考了和修改了 DroidAirPlay项目 , 和Airplay 协议 1, 将DroidAirPlay 下载下来 2, Eclipse 新建一个 ...
- CodeForces 385C Bear and Prime Numbers 素数打表
第一眼看这道题目的时候觉得可能会很难也看不太懂,但是看了给出的Hint之后思路就十分清晰了 Consider the first sample. Overall, the first sample h ...
- ASP.NET给Table动态添加删除行,并且得到控件的值
ASP.NET给Table动态添加控件并且得到控件的值 由于跟老师做一个小的项目,可是我自己又不太懂js,所以一直为动态建立表格并且能动态的取值和赋值感到苦恼.起初在网上找到了一些js资源,解决了动态 ...