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

● 归并排序

 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. inf 启动

    How to install an INF file using Delphi If you need to install an "inf" file using Delphi, ...

  2. Intellij IDEA神器值得收藏的小技巧

    概述 Intellij IDEA真是越用越觉得它强大,它总是在我们写代码的时候,不时给我们来个小惊喜.出于对Intellij IDEA的喜爱,我决定写一个与其相关的专栏或者系列,把一些好用的Intel ...

  3. 简单说throw和throws的区别

    1. 区别 throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是指抛出的一个具体的异常类型. 2.分别介绍 ...

  4. html json 导出Excel

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. ALGO-117_蓝桥杯_算法训练_友好数

    问题描述 有两个整数,如果每个整数的约数和(除了它本身以外)等于对方,我们就称这对数是友好的.例如: 9的约数和有:+= 4的约数和有:+= 所以9和4不是友好的. 220的约数和有: = 284的约 ...

  6. 求1~n整数中1出现的次数(《剑指offer》面试题43)

    题意: 给定一个整数n,求1~n这n个整数中十进制表示中1出现的次数. 思路: 方法1:最直观的是,对于1~n中的每个整数,分别判断n中的1的个数,具体见<剑指offer>.这种方法的时间 ...

  7. python学习疑问

    1.(已解决) test = [1, 2, 3, 4] ", id(test)) def func(a): ", id(a)) a = a.remove(1) ", id ...

  8. sass之为什么要使用预处理器

    使用预处理器主要目的就是编写出可读性更好.更易于维护的css. 以sass为例,sass中提供了@import可以在sass文件中导入其他sass文件,或在选择器中按需导入所需要的某个属性样式: @i ...

  9. PAT 乙级 1014 福尔摩斯的约会 (20) C++版

    1014. 福尔摩斯的约会 (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 大侦探福尔摩斯接到一张奇怪的 ...

  10. [UE4]在AI Character中要获得AI的controller,需要使用Get AIController