"令人迷惑的奇偶排序"
奇偶排序
出处: Java 数据结构与算法课后编程题 简单排序 3.4
原句
3.4还有一种简单排序算法是奇偶排序。
它的思路是在数组中重复两趟扫描。第一趟扫描选择所有的数据项对,a[i]和 a[j+1],j是奇数(j=1,3,5,……)。
如果它们的关键字的值次序颠倒,就交换它们。
第二趟扫描对所有的偶数数据项进行同样的操作(j=2,4,6,……)。
重复进行这样两趟的排序直到数组全部有序。
用oddEvenSort()方法替换bubbleSort.java程序(清单3.1)中的bubbleSort()方法。
确保它可以在不同数据量的排序中运行,还需要算出两趟扫描的次数。
解读
原话给出的思路可以看出十分清晰了(前面的几道题也是, 给出的思路也十分清晰明了, 虽然少但是给人感觉就是一下子就能看得懂)
一句话概括
一个数组, 先从奇数位开始比较相邻俩数据, 然后从偶数位开始比较相邻俩数据. 每次都是比较相邻两元素.
先贴代码
public class ArrayBub {
private long[] a;
private int nElems;
//
public ArrayBub(int max) {
a = new long[max];
nElems = 0;
}
//
public void insert(long newV) {
a[nElems++] = newV;
}
//
public void display() {
for (int i = 0 ; i < nElems; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
//
public void oddEvenSort() {
int oe;
boolean sorted = false;
int i;
while (!sorted) {
sorted = true;
for (oe = 0; oe < 2; oe++) {
//平行遍历, 先后作为起点
for (i = oe; i < nElems-1; i+=2) {
if (a[i] > a[i+1]) {
sorted = false;
//说明有非升序数对, 修改布尔值表示需要继续排序
//遇到非升序数对
swap(i, i+1);
}
}
}
}
}
//
public void swap(int one, int two) {
long temp = a[one];
a[one] = a[two];
a[two] = temp;
}
//看似交换坐标, 实际交换对应坐标的值交换
}
//验证
public class ArrayBubApp {
public static void main(String[] args) {
int maxSize = 10;
//
ArrayBub arr3;
arr3 = new ArrayBub(maxSize);
arr3.insert(7);
arr3.insert(8);
arr3.insert(6);
arr3.insert(5);
arr3.insert(4);
arr3.insert(3);
arr3.insert(2);
arr3.insert(1);
arr3.insert(0);
arr3.insert(-1);
//
System.out.println("odd 前");
arr3.display();
//
System.out.println("odd 后");
arr3.oddEvenSort();
arr3.display();
}
}
//控制台输出
odd 前
7 8 6 5 4 3 2 1 0 -1
odd 后
-1 0 1 2 3 4 5 6 7 8
代码分析
1.这个代码很特别的地方, 如果是写过冒泡排序, 你以为那个用从 n 开始动态递减的 out
作为遍历终点从而控制遍历的终点已经够奇妙了, 那么这里你肯定也会感觉很新颖.
虽然不是循环终点, 但是这里外循环控制的是起点, 用的是从 0 到 1, 控制的是每次开始的起点.
2.每次 i 的变化跳到下一个奇偶位, 比较的, 还是相邻两个元素, 这个不变.
实际调试时会发现黄色条跳得很莫名其妙, 这是整个调试过程的录制动图
看完后人只想缓缓地在脑门上画一个问号, 完全没有很直观的变化趋势.
这时, 可以在纸上写一遍, 毕竟太莫名其妙了.
实验数据用的是
7 8 6 5 4 3 2 1
作图
卖家秀
买家秀
这个时候还看不出什么,
虽然从头到尾写了一遍, 但还是不知道它怎么就莫名其妙地变成升序了——缓缓打出一个蛤??
但是至少写一遍后知道了两两对比之后 2 个元素就会变成有序(下括号标出的数对总是有序的), 这一点在第一轮偶数对是最直观的.
还是不能看出它是怎么做到排序的.
这个时候不妨将数据改成人的身高, 看看它们是怎么排序的.(模拟棒球运动员按身高整队)
从图中可以看出, 一米八被不知不觉地换到了最后一个位置.
倒数一轮也是, 1.2
被移动到了 1.3
前面, 刚好在 1.1
的后面
说到 1.1
, 它也被从后面换到最前面来了
整体上, 一米八
的位置从左上角作右下角呈现一条 下划线
, 一米七
也是. 一米六
也是先 下划线
然后 折回来
回想冒泡排序的原理, 可以知道, 它是比较相邻两个元素, 然后, 最大的被调到了最后面. (通俗来说就是一直找更大的)
要实现那样的话, 肯定数组内所有元素两两都比较过才能确定最后是升序排列.
这道题目和冒泡之间的联系就是它肯定也经过两两之间的比较.
这个时候再来会看上面的 一米八
:
原来是在奇数位, 然后是偶数, 相邻之间两两比较, 不断比较不断被换到右边, 直到来到最后一个位置.
然后, 会发现, 其它所有的元素都是这样, 原来的奇数位的数字, 下一个会出现在偶数位, 然后两两比较.
就这样, 每两两个元素都会先后经过相互之间的比较. 最后总是得到更大(更小)然后被移动到了前面或者后面.
结束语
原来, 奇偶数排序的原理实际上和冒泡是一样的, 通过让所有元素两两之间经过相互比较, 最后确定最大值, 最小值也会经过比较被换到最前面.
这也是为什么有博客会说
Odd-Even Sort
This is basically a variation of bubble-sort.
所以说, 奇偶排序写起来并不困难, 2 个 0
和 1
作为起点作不同的遍历. 比较 相邻
的元素.
是怎么做到排序的呢? 实际上和冒泡的原理一样, 也是让相邻元素两两经过不同顺序的相互比较, 直到最小的被移到最前, 最大的被移到了最后.