▶ 书中第二章部分程序,加上自己补充的代码,包括若干种归并排序,以及利用归并排序计算数组逆序数

● 归并排序

 package package01;

 import java.util.Comparator;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01
{
private class01() {} private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) // 归并两个排好序的子数组
{
for (int k = lo; k <= hi; k++)
aux[k] = a[k]; int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid) // 后段剩余
a[k] = aux[j++];
else if (j > hi) // 前段剩余
a[k] = aux[i++];
else if (less(aux[j], aux[i])) // 比较
a[k] = aux[j++];
else
a[k] = aux[i++];
}
} private static void sortTDKernel(Comparable[] a, Comparable[] aux, int lo, int hi) // 排序递归内核
{
if (hi <= lo)
return;
int mid = lo + (hi - lo) / 2;
sortTDKernel(a, aux, lo, mid);
sortTDKernel(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
} public static void sortTD(Comparable[] a) // 自顶向下的归并排序
{
Comparable[] aux = new Comparable[a.length]; // 统一分配临时内存
sortTDKernel(a, aux, 0, a.length - 1);
} private static void indexMerge(Comparable[] a, int[] index, int[] aux, int lo, int mid, int hi) // 间接排序的归并
{
for (int k = lo; k <= hi; k++)
aux[k] = index[k]; int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
index[k] = aux[j++];
else if (j > hi)
index[k] = aux[i++];
else if (less(a[aux[j]], a[aux[i]]))
index[k] = aux[j++];
else
index[k] = aux[i++];
}
} private static void indexSortTDKernel(Comparable[] a, int[] index, int[] aux, int lo, int hi) // 间接排序递归内核
{
if (hi <= lo)
return;
int mid = lo + (hi - lo) / 2;
indexSortTDKernel(a, index, aux, lo, mid);
indexSortTDKernel(a, index, aux, mid + 1, hi);
indexMerge(a, index, aux, lo, mid, hi);
} public static int[] indexSortTD(Comparable[] a) // 自顶向下的间接归并排序
{
int n = a.length;
int[] aux = new int[n];
int[] index = new int[n];
for (int i = 0; i < n; i++)
index[i] = i; indexSortTDKernel(a, index, aux, 0, n - 1);
return index;
} public static void sortBU(Comparable[] a) // 自底向上的归并排序,不需要递归,合并子数组的函数与前面相同
{
int n = a.length;
Comparable[] aux = new Comparable[n];
for (int len = 1; len < n; len *= 2)
{
for (int lo = 0; lo < n - len; lo += len + len)
{
int mid = lo + len - 1;
int hi = Math.min(lo + len + len - 1, n - 1);
merge(a, aux, lo, mid, hi);
}
}
} // 改良版本
private static final int CUTOFF = 7; // 小于该尺寸的数组使用插入排序 private static void merge2(Comparable[] src, Comparable[] dst, int lo, int mid, int hi) // 区分原数组和目标数组,减少拷贝
{
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
dst[k] = src[j++];
else if (j > hi)
dst[k] = src[i++];
else if (less(src[j], src[i]))
dst[k] = src[j++];
else
dst[k] = src[i++];
}
} private static void sort2TDKernel(Comparable[] src, Comparable[] dst, int lo, int hi)
{
if (hi <= lo + CUTOFF) // 数据较少时使用插入排序
{
insertionSort(dst, lo, hi);
return;
}
int mid = lo + (hi - lo) / 2;
sort2TDKernel(dst, src, lo, mid);
sort2TDKernel(dst, src, mid + 1, hi); if (!less(src[mid + 1], src[mid])) // src[mid+1] >= src[mid],不用归并了
System.arraycopy(src, lo, dst, lo, hi - lo + 1); // 数组拷贝,快于 for (int i = lo; i <= hi; i++) dst[i] = src[i];
else
merge2(src, dst, lo, mid, hi);
} public static void sort2TD(Comparable[] a)
{
Comparable[] aux = a.clone();
sort2TDKernel(aux, a, 0, a.length - 1);
} private static void insertionSort(Comparable[] a, int lo, int hi)
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && less(a[j], a[j - 1]); j--)
exch(a, j, j - 1);
}
} private static void exch(Comparable[] a, int i, int j) // 插入排序用到的交换
{
Comparable swap = a[i];
a[i] = a[j];
a[j] = swap;
} private static void merge2(Object[] src, Object[] dst, int lo, int mid, int hi, Comparator comparator) // 自定义类型的版本(同上 5 个函数)
{
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
dst[k] = src[j++];
else if (j > hi)
dst[k] = src[i++];
else if (less(src[j], src[i], comparator))
dst[k] = src[j++];
else
dst[k] = src[i++];
}
} private static void sort2TDKernel(Object[] src, Object[] dst, int lo, int hi, Comparator comparator)
{
if (hi <= lo + CUTOFF)
{
insertionSort(dst, lo, hi, comparator);
return;
} int mid = lo + (hi - lo) / 2;
sort2TDKernel(dst, src, lo, mid, comparator);
sort2TDKernel(dst, src, mid + 1, hi, comparator); if (!less(src[mid + 1], src[mid], comparator))
System.arraycopy(src, lo, dst, lo, hi - lo + 1);
else
merge2(src, dst, lo, mid, hi, comparator);
} public static void sort2TD(Object[] a, Comparator comparator)
{
Object[] aux = a.clone();
sort2TDKernel(aux, a, 0, a.length - 1, comparator);
} private static void insertionSort(Object[] a, int lo, int hi, Comparator comparator)
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && less(a[j], a[j - 1], comparator); j--)
exch(a, j, j - 1);
}
} private static void exch(Object[] a, int i, int j)
{
Object swap = a[i];
a[i] = a[j];
a[j] = swap;
} private static boolean less(Comparable a, Comparable b) // 各排序都用到的比较函数
{
return a.compareTo(b) < 0;
} private static boolean less(Object a, Object b, Comparator comparator) // 自定义类型的比较函数
{
return comparator.compare(a, b) < 0;
} private static void show(Comparable[] a)
{
for (int i = 0; i < a.length; i++)
StdOut.println(a[i]);
} public static void main(String[] args)
{
String[] a = StdIn.readAllStrings();
//int[] index = class01.indexSortTD(a); class01.sortTD(a);
//class01.sortBU(a);
//class01.sort2TD(a);
//for (int i = 0; i<a.length; i++)
// StdOut.println(index[i]);
System.out.printf("\nFinish!\n");
}
}

● 利用归并排序来计算数组的逆序数,只注释了与归并排序不一样的地方

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut; public class class01
{
private class01() {} private static long merge(int[] a, int[] aux, int lo, int mid, int hi) // 限定输入为 int 数组
{
long inversions = 0; for (int k = lo; k <= hi; k++)
aux[k] = a[k]; int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
a[k] = aux[j++];
else if (j > hi)
a[k] = aux[i++];
else if (aux[j] < aux[i]) // 算术比较
{
a[k] = aux[j++];
inversions += (mid - i + 1); // 多了一步计算
}
else
a[k] = aux[i++];
}
return inversions; // 返回逆序数
} private static long count(int[] a, int[] b, int[] aux, int lo, int hi) // 部分计数函数
{
long inversions = 0;
if (hi <= lo)
return 0;
int mid = lo + (hi - lo) / 2;
inversions += count(a, b, aux, lo, mid); // 分治和归并的部分补上计算
inversions += count(a, b, aux, mid + 1, hi);
inversions += merge(b, aux, lo, mid, hi);
return inversions;
} public static long count(int[] a) // 可调用的计数函数
{
int[] b = new int[a.length];
int[] aux = new int[a.length];
for (int i = 0; i < a.length; i++)
b[i] = a[i];
return count(a, b, aux, 0, a.length - 1);
} private static long brute(int[] a, int lo, int hi) // 枚举方法计算逆序数
{
long inversions = 0;
for (int i = lo; i <= hi; i++)
{
for (int j = i + 1; j <= hi; j++)
if (a[j] < a[i])
inversions++;
}
return inversions;
} // 自定义类型版本
private static <Key extends Comparable<Key>> long merge(Key[] a, Key[] aux, int lo, int mid, int hi)
{
long inversions = 0; for (int k = lo; k <= hi; k++)
aux[k] = a[k]; int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
a[k] = aux[j++];
else if (j > hi)
a[k] = aux[i++];
else if (less(aux[j], aux[i])) // 比较方法改回去了
{
a[k] = aux[j++];
inversions += (mid - i + 1);
}
else
a[k] = aux[i++];
}
return inversions;
} private static <Key extends Comparable<Key>> boolean less(Key v, Key w)
{
return (v.compareTo(w) < 0);
} private static <Key extends Comparable<Key>> long count(Key[] a, Key[] b, Key[] aux, int lo, int hi)
{
long inversions = 0;
if (hi <= lo)
return 0;
int mid = lo + (hi - lo) / 2;
inversions += count(a, b, aux, lo, mid);
inversions += count(a, b, aux, mid + 1, hi);
inversions += merge(b, aux, lo, mid, hi);
return inversions;
} public static <Key extends Comparable<Key>> long count(Key[] a)
{
Key[] b = a.clone();
Key[] aux = a.clone();
return count(a, b, aux, 0, a.length - 1);
} private static <Key extends Comparable<Key>> long brute(Key[] a, int lo, int hi)
{
long inversions = 0;
for (int i = lo; i <= hi; i++)
{
for (int j = i + 1; j <= hi; j++)
if (less(a[j], a[i]))
inversions++;
}
return inversions;
} public static void main(String[] args) // 使用文件名而不是重定向来作为输入
{
In in = new In(args[0]);
int[] a = in.readAllInts();
int n = a.length;
int[] b = new int[n];
for (int i = 0; i<n; i++)
b[i] = a[i]; StdOut.println(class01.count(a));
StdOut.println(class01.count(b));
}
}

《算法》第二章部分程序 part 2的更多相关文章

  1. 《算法》第二章部分程序 part 5

    ▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...

  2. 《算法》第二章部分程序 part 4

    ▶ 书中第二章部分程序,加上自己补充的代码,包括优先队列和索引优先队列 ● 优先队列 package package01; import java.util.Comparator; import ja ...

  3. 《算法》第二章部分程序 part 3

    ▶ 书中第二章部分程序,加上自己补充的代码,包括各种优化的快排 package package01; import edu.princeton.cs.algs4.In; import edu.prin ...

  4. 《算法》第二章部分程序 part 1

    ▶ 书中第二章部分程序,加上自己补充的代码,包括插入排序,选择排序,Shell 排序 ● 插入排序 package package01; import java.util.Comparator; im ...

  5. javascript数据结构和算法 第二章 (数组) 二

    字符串表示的数组 join() 和 toString() 函数返回数组的字符串表示.这两个函数通过将数组中的元素用逗号分隔符切割,返回字符串数组表示. 这里有个样例: var names = [&qu ...

  6. 第二章--Win32程序运行原理 (部分概念及代码讲解)

    学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...

  7. java版数据结构与算法第二章数组

    数组由一组具有相同类型的数据元素组成,并存储在一组连续存储单元中.一维数组是常量. 二维数组:若一维数组中的数据元素又是一堆数据结构,我们称之为二维数组.二维数组可以看成是n个列向量组成的线性表. 数 ...

  8. ASP.NET本质论第二章应用程序对象学习笔记1

    1.请求的处理参数—上下文对象HttpContext 1) 针对每一次请求,ASP.NET将创建一个处理这次请求所使用的HttpContext对象实例,这个对象实例将用来在ASP.NET服务器的处理过 ...

  9. 【学习总结】java数据结构和算法-第二章-数据结构和算法概述

    总目录链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 数据结构和算法的关系 几个实际编程中的问题 线性结构和非线性结构 数据结构和算法的关系 几个实际编程中 ...

随机推荐

  1. backgroud 应用减小资源大小和请求数

    一,一个典型的应用,利用小图的自动延伸,实现整个网页背景图,充分节约资源宽带.如:汽车之家的404页背景图就是这样 <div style="height: 3000px; backgr ...

  2. [VC6,VC9] [ts,nts,deb] [rpm,msi] 你需要下载什么格式的文件

    1.VC6与VC9的区别 VC6版本是使用Visual Studio 6编译器编译的,如果你的PHP是用Apache来架设的,那你就选择VC6版本. VC9版本是使用Visual Studio 200 ...

  3. PHP $a='abcdef';请取出$a的值并打印第一个字母

    echo $a[0];echo $a{0};echo chr(ord($a));echo substr( $a, 0,1);

  4. P3811 乘法逆元

    传送 乘法逆元:ax ≡ 1 (mod p),其中x为a的逆元,求模意义下的乘法逆元,通常有一下几种方法: 1.拓展欧几里得(也就是exgcd) ax ≡ 1 (mod p) ax-py=1 这就变成 ...

  5. Apollo分布式配置中心部署以及使用

    一.简介Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理场 ...

  6. Sqoop-1.4.6安装部署及详细使用介绍

    之所以选择Sqoop1是因为Sqoop2目前问题太多.无法正常使用,综合比较后选择Sqoop1. Sqoop1安装配置比较简单 一.安装部署 (1).下载安装包 下载地址:http://archive ...

  7. spring4.0之八:Groovy DSL

    4.0的一个重要特征就是完全支持Groovy,Groovy是Spring主导的一门基于JVM的脚本语言(动态语言).在spring 2.x,脚本语言通过 Java scripting engine在S ...

  8. 【ZZ】详解哈希表的查找

    详解哈希表的查找 https://mp.weixin.qq.com/s/j2j9gS62L-mmOH4p89OTKQ 详解哈希表的查找 2018-03-01 算法与数据结构 来自:静默虚空 http: ...

  9. MySQL binlog 企业案例升级版

    需求:1.创建一个数据库 oldboy2.在oldboy下创建一张表t13.插入5行任意数据4.全备5.插入两行数据,任意修改3行数据,删除1行数据6.删除所有数据7.再t1中又插入5行新数据,修改3 ...

  10. 知识点:java 注解 @SuppressWarnings

    前言: 简介:java.lang.SuppressWarnings是J2SE5.0中标准的Annotation之一.可以标注在类.字段.方法.参数.构造方法,以及局部变量上.作用:告诉编译器忽略指定的 ...