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

● 归并排序

 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. iCheck .js各种各样的插件 fuck Javascript

    http://www.bootcss.com/p/icheck/ 1.先看下网上下载的demo <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...

  2. Boost--lexical_cast 一个方便安全高效的string转换库

    #include "boost\lexical_cast.hpp" #include <vector> #include <iostream> #inclu ...

  3. bzoj5043: 密码破译

    Description 小Q发明了一个新的加密算法,对于一个长度为n的非负整数序列a_1,a_2,...,a_n,他会随机选择一个非负整数k, 将每个数都异或上k得到b_1,b_2,...,b_n,即 ...

  4. 《Java并发编程实战》笔记-Happens-Before规则

    Happens-Before规则 程序顺序规则.如果程序中操作A在操作B之前,那么在线程中A操作将在B操作之前执行. 监视器锁规则.在监视器锁上的解锁操作必须在同一个监视器锁上的加锁操作之前执行. v ...

  5. 服务网关zuul之四:zuul网关配置

    禁用过滤器在Zuul中特别提供了一个参数来禁用指定的过滤器,该参数的配置格式如下:zuul.AccessFilter.pre.disable=true动态加载动态路由通过结合Spring Cloud ...

  6. springboot(五)读写分离,多个读库,Druid监控--待整理

    1.修改mybatis.properties # 主数据源,默认的 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.d ...

  7. ubuntu的一些常用命令及疑难杂症

    记录ubuntu下各种注意事项及常用命令 1,发热:因为硬件厂商对linux类系统的支持不足,驱动不会自动安装,所以要自己装... http://www.linuxidc.com/Linux/2015 ...

  8. python图片和字符串的转换

    有个业务,需要将图片压缩转化为64位编码上传到服务端. import json,requests,base64 #网上下载图片素材 r = requests.get("https://tim ...

  9. 中级 jQuery 了解

    初级阶段的知识已经结束:中级要接触的东西:jQuery  php  css3  移动端: get Context("2d")   2d画布: draw Image()     绘制 ...

  10. ospf精确宣告地址

    ospf的一点小问题 http://bbs.51cto.com/thread-881459-1.html 参照博客地址 network 172.20.1.0 0.0.0.3 area 0 networ ...