排序按时间复杂度和空间复杂度可分为 低级排序 和 高级排序 算法两种。下面将对排序算法进行讲解,以及样例的展示。

低级排序:冒泡排序、选择排序、插入排序。  

  冒泡排序:

核心思想,小的数往前移。假设最小的数在最后一位,将最后一位一步步移到第一位。

public void bubbleSort(int[] list) {
int n = list.length - 1;
for(int i = 0; i < n; i ++) {
for(int j = 0; j < n - i; j ++) {
if(list[j] > list[j + 1])
swap(j, j + 1, list);
}
}
}
public void swap(int i, int j, int[]list) {
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}

  选择排序:

选择最小数按顺序排列。从当前未排序的数组中,找出一个最小的数,放在第一位。第二小的放在第二位······

public void selectSort(int[] list) {
int min; //记录最小下标
for(int i = 0; i < list.length - 1; i ++) { //对n个数排序,只需将n-1个数排好序,就ok了。所以循环条件是list.length-1.
min = i;
for(int j = i + 1; j < list.length; j ++) { //循环一次找出一个最小数
if(list[j] < list[min]) {
min = j;
}
}
swap(i, min, list);
}
}
public void swap(int i, int j, int[]list) {
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}

  插入排序:

取出元素,从后往前依次比较前面的元素。直到前面的数比自己小,则插入到当前位置。在此过程中,大于或等于自己的元素一直往后移位。

public void insertSort(int[] list) {
int sign, temp; // sign记录空值下标,temp记录取出值
for(int i = 1; i < list.length; i ++) {
temp = list[i];
sign = i;
//如果取出值小于前一个值,则把前一个值往后移,覆盖当前值
while(sign > 0 && list[sign - 1] > temp) {
list[sign] = list[sign - 1];
sign --;
}
list[sign] = temp;
}
}

插入排序优化写法:

//优化插入:将数组第一个元素用来保存数据,达到减少比较次数
public void insertSort_2(int[] list) {
int sign, temp; // sign记录空值下标,temp记录取出值
for(int i = 2; i < list.length; i ++) {
temp = list[i];
list[0] = temp;
sign = i - 1;
//如果取出值小于前一个值,则把前一个值往后移,覆盖当前值
while(list[sign] > temp) {
list[sign + 1] = list[sign];
sign --;
}
list[sign + 1] = temp;
}
}

高级排序:快速排序、归并排序。

  快速排序:
最流行的排序算法、速度最快的排序算法。选定一个枢轴,小于枢轴的数放左边,大于枢轴的数放右边,交换枢轴两边的数。
public void quickSort(int left, int right, int[] list) {
//选枢轴进行划分
if(left < right) {
int i = left;
int j = right + 1;
int privot = list[left]; //定义一个枢轴
do{
do{
i ++;
}while(list[i] < privot);//找到一个比枢轴大的数
do{
--j;
}while(list[j] > privot);//找到一个比枢轴小的数
if(i<j) swap(i, j, list);
}while(i < j); swap(left, j, list); //将基准数放置到中间 quickSort(left, j - 1, list);
quickSort(j + 1, right, list);
}
}
public void swap(int i, int j, int[]list) {
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}

  归并排序:

将两个排好序的数组合并在一起,并且重新排序。比如1->2>3 、1->4->5 合并在一起后就是:1->2>3 ->1->4->5  排好序为:1->1->2->3->4->5.   在此演示的示例为直接合并的数组。

  首先,为方便写程序,数组第一个元素将废弃使用,不对其进行排序。

基础归并函数:归并两个排序的数组

public void Merge(int[] initList, int[] mergeList, int l, int m, int n) {    
   //  initList 初始化数组, mergeList存放排好序的数组。
// l表示第一个数组下标,m表示第一个数组最后一个元素下标,n表示第二个数组最后一个元素下标。result表示新建数组下标
int i1, i2, result;
for(i1 = l, i2 = m + 1, result = i1; i1 <= m && i2 <= n; result ++) {
if(initList[i1] <= initList[i2]) {
mergeList[result] = initList[i1];
i1 ++;
}else {
mergeList[result] = initList[i2];
i2 ++;
}
}
  //  将第一个数组和第二个数组未放进mergeList的元素复制到mergeList中。(如果没有剩余元素,则复制元素个数为0,不产生影响,所以可以放心对两个数组都进行剩余元素复制)
System.arraycopy(initList, i1, mergeList, result, m - i1 + 1);
System.arraycopy(initList, i2, mergeList, result, n - i2 + 1);
}

其次,有了前面的基础归并函数,那么就可以实现乱序数组的归并排序。其思想,进行多次基础归并。

     

实现单次归并:划分数组进行归并。第一次单个元素作为划分对象,第二次两个元素作为划分对象·········

public void MergePass(int[] initList, int[] mergeList, int n, int s) {  //  n表示初始化数组最后一位元素下标,s表示第几次归并。
int i;
for(i = 1; i <= n - 2*s + 1; i += 2*s) {   //对划分的数组两两归并
Merge(initList, mergeList, i, i + s - 1, i + 2*s - 1);
} if((i + s - 1) < n) {  //有剩余未归并的元素则进行归并
Merge(initList, mergeList, i, i + s - 1, n);
}else {    //将剩余元素拷贝下来
System.arraycopy(initList, i, mergeList, i, n + 1 - i);
}
}

  最后通过控制归并次数,真正达到乱序数组归并排序的效果:

public void MergeSort(int[] list) {
int[] newList = new int[list.length];   for(int i = 1; i < list.length; i *= 2) {
MergePass(list, newList, list.length - 1, i);
i *= 2;    //只所以在此进行i*2,是因为归并后的结果放在newList里面,重新进行归并时。省掉将newList重新拷贝到list的麻烦
MergePass(newList, list, list.length - 1, i);
}
}

接下来,来个归并算法的全家桶吧:

public class MergeSort {
@Test
public void fun() {
int[] a = {0, 23, 47, 81, 95, 7, 14, 39, 55, 62, 74};
MergeSort(a);
for(int i : a) {
System.out.print(i + "\t");
}
}
public void Merge(int[] initList, int[] mergeList, int l, int m, int n) {
// l表示第一个数组下标,m表示最后一个数组下标,result表示新建数组下标
int i1, i2, result;
for(i1 = l, i2 = m + 1, result = i1; i1 <= m && i2 <= n; result ++) {
if(initList[i1] <= initList[i2]) {
mergeList[result] = initList[i1];
i1 ++;
}else {
mergeList[result] = initList[i2];
i2 ++;
}
}
System.arraycopy(initList, i1, mergeList, result, m - i1 + 1);
System.arraycopy(initList, i2, mergeList, result, n - i2 + 1);
}
public void MergePass(int[] initList, int[] mergeList, int n, int s) {
int i;
for(i = 1; i <= n - 2*s + 1; i += 2*s) {
Merge(initList, mergeList, i, i + s - 1, i + 2*s - 1);
} if((i + s - 1) < n) {
Merge(initList, mergeList, i, i + s - 1, n);
}else {
System.arraycopy(initList, i, mergeList, i, n + 1 - i);
}
}
public void MergeSort(int[] list) {
int[] newList = new int[list.length];
for(int i = 1; i < list.length; i *= 2) {
MergePass(list, newList, list.length - 1, i);
i *= 2;
MergePass(newList, list, list.length - 1, i);
}
}
}

数据结构Java版之排序算法(二)的更多相关文章

  1. Java版各种排序算法 (冒泡,快速,选择,插入)

    package com.test4; import java.util.*; //Calendar 显示时间 /** * @author qingfeng * 功能:排序算法 */ public cl ...

  2. 数据结构Java版之查找算法(三)

    关于查找算法,这里只进行两个算法的说明.包括 顺序查找 和 折半查找. 顺序查找: 顺序查找常用于未排序的数据中.查找速度较慢,只能应用于较小的数据量. public int sequentialSe ...

  3. 数据结构Java版之交换算法(一)

    交换的本质是拷贝,其中拷贝包括两种方式.值拷贝和指针拷贝,在java中没有指针,为此,我们可以理解为地址拷贝,在我看来,指针就是地址. 1.传值方式示例: 由上述示例可得,传值,不能起到交换的作用,原 ...

  4. Java中的排序算法(2)

    Java中的排序算法(2) * 快速排序 * 快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists). * 步骤为: * 1. 从数 ...

  5. java实现各种排序算法

    java实现各种排序算法 import java.util.Arrays; public class SomeSort { public static void main(String[] args) ...

  6. Java数据结构(七)—— 排序算法

    排序算法(Sort Algorithm) 排序算法介绍和分类 将一组数据,依指定顺序进行排列 排序的分类 内部排序 指将需要处理的所有数据都加载到内部存储器中进行排序 外部排序 数据量过大,无法全部加 ...

  7. java实现八大排序算法

    Arrays.sort() 采用了2种排序算法 -- 基本类型数据使用快速排序法,对象数组使用归并排序. java的Collections.sort算法调用的是归并排序,它是稳定排序 方法一:直接插入 ...

  8. java实现折半排序算法

    折半插入排序法,又称二分插入排序法,是直接插入排序法的改良版,也需要执行i-1趟插入,不同之处在于,第i趟插入,先找出第i+1个元素应该插入的的位置,假定前i个数据是已经处于有序状态. 折半插入排序( ...

  9. JAVA简单选择排序算法原理及实现

    简单选择排序:(选出最小值,放在第一位,然后第一位向后推移,如此循环)第一位与后面每一个逐个比较,每次都使最小的置顶,第一位向后推进(即刚选定的第一位是最小值,不再参与比较,比较次数减1) 复杂度: ...

随机推荐

  1. [JZOJ5281]钦点题解--瞎搞+链表

    [JZOJ5281]钦点题解--瞎搞+链表 题目链接 于 暴 力 过

  2. Java源码阅读之ArrayList

    基于jdk1.8的ArrayList源码分析. 实现List接口最常见的大概就四种,ArrayList, LinkedList, Vector, Stack实现,今天就着重看一下ArrayList的源 ...

  3. .NET 对文件和文件夹操作的介绍

    1 Directory和File类只包含静态方法,不能被实例化 2 DirectoryInfo和FileInfo他们是有状态的,需要被实例化 //构造函数初始化一个文件的路径 FileInfo myF ...

  4. [LeetCode] 121. 买卖股票的最佳时机 ☆(动态规划)

    https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/xiang-xi-tong-su-de-si-lu- ...

  5. 简单使用auth认证实现登录注册

    1 添加路由 //注册 Route::get('/register',"RegisterController@index"); Route::post('/register',&q ...

  6. Django drf:手撸自定义跨域

    项目需求: 1.用域名8000向8001发送请求,用django框架解决跨域问题 2.用上自定义中间件配置,支持get.post.put.detele和非简单请求 3.支持版本控制 4.在settin ...

  7. VGridControl 使用技巧

    1. 让列的宽度自动填充 如果VGridControl的LayoutStyle属性为BandsView或SingleRecordView,那么把VGridControl的OptionsView.Aut ...

  8. /tmp/supervisor.sock no such file 报错

    背景: 在执行 supervisorctl 时,报了这么一个错(如图),查找对应文档后解决,记录下来用来以后遇到使用 解决: 1. 将 supervisord.conf 文件下对应的 /tmp  目录 ...

  9. 性能三 powerVR specfication

    2.Optimising Geometry Interleaving Attributes VBO Draw call size Triangle Size  32个像素/primitive    - ...

  10. JVM 平台上的 Scheme 语言实现 JSchemeMin

    JSchemeMin 是一个JVM平台上的Scheme语言实现. 作为R7RS的实现,JSchemeMin支持Scheme的所有标准特性,包括头等公民地位的过程.尾递归优化.继续.用户定义记录.库(包 ...