您的位置:首页 > 其它

排序算法一(直接选择,堆排序,冒泡排序和快速排序)

2011-10-26 21:12 447 查看
对于一个排序算法来说,一般从如下3个方面衡量算法的优劣:

1.时间复杂度:它主要是分析关键字的比较次数和记录的移动次数

2.空间复杂度:分析排序算法中需要多少辅助内存

3.稳定性:若两个记录A和B的关键字相等,排序前后二者的先后次序没有发生变化就称之为稳定排序

现有的排序算法分为:内部排序和外部排序

内部排序:所有的操作都是在内存中完成的,而外部排序需要借助外部存储器(如磁盘等)

外部排序最常用的方法是多路归并排序,即将原先的文件分解为多个能够一次性装入内存的部分,

分别把每一部分调入内存完成排序,接下来再对多个有序的子文件进行归并排序。

接下来主要介绍内部排序,分为:

选择排序(直接选择和堆排序),交换排序(冒泡和快速),插入排序(直接插入,折半插入和Shell排序),归并排序,基数排序和桶式排序。

本文介绍将介绍选择排序和交换排序

数组元素类DataWrap:flag用来标记相同元素出现的次数,a 表示第一次出现,b表示第二次出现,以此类推,用来测试算法的稳定性

package sort_lyf;

public class DataWrap implements Comparable<DataWrap> {
int data;
String flag;
public DataWrap(int data,String flag){
this.data = data;
this.flag = flag;
}
public String toString(){
return data+flag;
}
public static void swap(DataWrap[] data, int i, int j) {
DataWrap temp = data[i];
data[i] = data[j];
data[j] = temp;
}
@Override
public int compareTo(DataWrap datawrap) {
return this.data > datawrap.data ? 1:(this.data == datawrap.data? 0:-1);
}
}

算法的接口类:ISort(采用策略模式)

package sort_lyf;

public interface ISort {
public void sort(DataWrap[] data);
}

算法的实现类:

package sort_lyf;
/**
* @author liyafang 直接选择排序:
* 程序将记录定位在第一个数据上,拿第一个数据和后边的数据依次比较,
* 如果第一个数据大于后边的数据,发生交换,这样第一趟下来,就选出
* 最小的一个元素了,它被排在了第一位,然后在定位第二个数据。
*/
public class DirectSelectSort implements ISort {
public  void sort(DataWrap[] data) {
System.out.println("开始进入直接选择排序:");
int arrayLength = data.length;
for (int i = 0; i < arrayLength - 1; i++) {// 外层循环需要遍历到倒数第二个元素
for (int j = i + 1; j < arrayLength; j++) {// 内层循环需要遍历到倒数第一元素
if (data[i].compareTo(data[j]) > 0) {
DataWrap.swap(data, i, j);
}
}
System.out.println(java.util.Arrays.toString(data));
}
// 存在的问题:在每趟比较过程中,程序一旦发现某个数据比第一
// 位的数据小,立即交换他们,这增加了交换次数,导致算法效率低下。
}
}
排序之前:
[21a, 30a, 49, 30b, 16, 9a, 9b, 21b]
开始进入直接选择排序:
[9a, 30a, 49, 30b, 21a, 16, 9b, 21b]
[9a, 9b, 49, 30b, 30a, 21a, 16, 21b]
[9a, 9b, 16, 49, 30a, 30b, 21a, 21b]
[9a, 9b, 16, 21a, 49, 30b, 30a, 21b]
[9a, 9b, 16, 21a, 21b, 49, 30a, 30b]
[9a, 9b, 16, 21a, 21b, 30a, 49, 30b]
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49]
排序之后:
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49][/code]


package sort_lyf;
/**
* @author liyafang 优化后的直接选择排序算法:
* 用一个变量记录本趟最小元素的索引,每趟选择
* 只发生一次交换
*/
public class DirectSelectSortOptimized implements ISort {
//
public void sort(DataWrap[] data) {
System.out.println("开始进入优化版的直接选择排序:");
int arrayLength = data.length;
for (int i = 0; i < arrayLength - 1; i++) {
int minIndex = i;// 永远保留本躺比较中最小值的索引
for (int j = i + 1; j < arrayLength; j++) {
if (data[minIndex].compareTo(data[j]) > 0) {
minIndex = j;
}
}
if (minIndex != i) {
DataWrap.swap(data, i, minIndex);
}
System.out.println(java.util.Arrays.toString(data));
}
}
// 小结:对于直接选择排序,假如有n项数据,数据交换的次数最多有n-1次
// 比较次数较多,时间复杂度为O(n*n),空间效率很高为O(1);是不稳定排序。
}
排序之前:
[21a, 30a, 49, 30b, 16, 9a, 9b, 21b]
开始进入优化版的直接选择排序:
[9a, 30a, 49, 30b, 16, 21a, 9b, 21b]
[9a, 9b, 49, 30b, 16, 21a, 30a, 21b]
[9a, 9b, 16, 30b, 49, 21a, 30a, 21b]
[9a, 9b, 16, 21a, 49, 30b, 30a, 21b]
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]
排序之后:
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]



package sort_lyf;
/**
* @author liyafang 堆排序:
* 对于一棵顺序结构的完全二叉树而言,对于索引为k的节点,它的两个子节点的索引分别为2k+1,2k+2,反过来,对于
* 节点为k的,父节点为(k-1)/2.堆排序的步骤就是重复一下两个步骤:1.建堆   2.拿堆的根节点和最后一个节点交换。
* 对于包含n个元素的数组,堆排序需要n-1次建堆,建堆从最后一个非叶节点开始,因为只要保证每个非叶子节点的值大
* 于等于其左右子节点的值。每次建堆的作用就是选出最大值(注意大堆排出来的是升序),实际上也属于选择排序,只
* 不过堆排序可以通过树形结构保存部分比较结果,可减少比较次数。
*/
public class HeapSort implements ISort {
public void sort(DataWrap[] data) {
System.out.println("开始进入堆排序");
int arrayLength = data.length;
for (int i = 0; i < arrayLength; i++) {
buildMaxHeap(data, arrayLength - 1 - i);// 每次建堆完成之后,堆顶元素为第i+1大元素
DataWrap.swap(data, 0, arrayLength - 1 - i);// 交换堆顶和arrayLength - 1
// - i元素
// 交换完成重新再次对其余元素建堆
System.out.println(java.util.Arrays.toString(data));
}
}

// 对data数组从0到lastIndex建最大堆,选出0到lastIndex索引范围内的最大元素(堆顶元素)
private void buildMaxHeap(DataWrap[] data, int lastIndex) {
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
int comparingIndex = i;// 当前正在判断的节点
while ((2 * comparingIndex + 1) <= lastIndex) {// 如果当先节点的左子节点还存在
int biggerIndex = 2 * comparingIndex + 1;// 左子节点的索引
if (biggerIndex < lastIndex) {// 如果右子节点存在
if (data[biggerIndex].compareTo(data[biggerIndex + 1]) < 0) {
biggerIndex++;
}
}
if (data[comparingIndex].compareTo(data[biggerIndex]) < 0) {
DataWrap.swap(data, comparingIndex, biggerIndex);
// 继续判断发生交换的子节点(biggerIndex)是否大于其左右子节点
comparingIndex = biggerIndex;
} else {
break;
}
}
}
}
// 小结:对于堆排序算法而言,需要进行n-1次建堆,每次建堆耗时logN,
// 则时间效率为O(N*logN),空间效率很高为O(1),不稳定排序。
}
排序之前:
[21a, 30a, 49, 30b, 16, 9a, 9b, 21b]
开始进入堆排序
[21b, 30a, 21a, 30b, 16, 9a, 9b, 49]
[9b, 30b, 21a, 21b, 16, 9a, 30a, 49]
[9a, 21b, 21a, 9b, 16, 30b, 30a, 49]
[9a, 16, 21a, 9b, 21b, 30b, 30a, 49]
[9b, 16, 9a, 21a, 21b, 30b, 30a, 49]
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]
[9b, 9a, 16, 21a, 21b, 30b, 30a, 49]
[9b, 9a, 16, 21a, 21b, 30b, 30a, 49]
排序之后:
[9b, 9a, 16, 21a, 21b, 30b, 30a, 49]
package sort_lyf;

/**
* @author liyafang 优化版的冒泡法:
* 依次比较0和1,1和2,2和3,n-2和n-1的值,如果前者大,就交换
* 经过第一趟,最大的元素排到了最后,然后进行第二趟... 一旦一
* 趟冒泡没有发生交换,即可提前结束排序。
*/
public class BubbleSortOptimized implements ISort {
public void sort(DataWrap[] data) {
System.out.println("开始进入改进版冒泡排序:");
int arrayLength = data.length;
int count = 0;
boolean IsSwap = false;
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength - 1 - i; j++) {
if (data[j].compareTo(data[j + 1]) > 0) {
DataWrap.swap(data, j, j + 1);
IsSwap = true;
count++;
}
}
if (!IsSwap) {// 如果某趟没有发生交换,则表明已处于有序状态
break;
}
System.out.println(java.util.Arrays.toString(data));
}
System.out.println("总的交换次数:" + count);
}
/**
* 冒泡排序而言的时间效率是不确定的:最好的情况下,初始数据序列已经处于有序的状态
* 执行一趟冒泡即可,做n-1次比较,无需进行任何交换;但在最坏情况下,初始数据序列
* 处于完全逆序,算法执行n-1躺冒泡,第i趟做了n-i次比较,执行n-i-1次对象交换,
* 此时交换总次数为n(n-1)/2;算法空间效率很高,为O(1); 属于稳定排序;
*/
}
排序之前:
[21a, 30a, 49, 30b, 16, 9a, 9b, 21b]
开始进入改进版冒泡排序:
[21a, 30a, 30b, 16, 9a, 9b, 21b, 49]
[21a, 30a, 16, 9a, 9b, 21b, 30b, 49]
[21a, 16, 9a, 9b, 21b, 30a, 30b, 49]
[16, 9a, 9b, 21a, 21b, 30a, 30b, 49]
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49]
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49]
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49]
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49]
总的交换次数:18
排序之后:
[9a, 9b, 16, 21a, 21b, 30a, 30b, 49]



package sort_lyf;
/**
* @author liyafang
*/
public class QuickSort implements ISort{
public  void sort(DataWrap[] data) {
System.out.println("开始进入快速排序:");
subSort(data, 0, data.length - 1);
System.out.println(java.util.Arrays.toString(data));
}

public  void subSort(DataWrap[] data, int start, int end) {
if (start < end) {
DataWrap base = data[start];
// 定一个变量leftIndex,从左边第一个索引开始
int leftIndex = start;
// 定一个变量rightIndex,从右边第一个索引开始
int rightIndex = end + 1;
// 此处三个while循环用的非常秒,注意体会!
while (true) {
// 找出大于分界值的元素的索引,并用leftIndex记录它
while (leftIndex < end
&& (data[++leftIndex].compareTo(base) <= 0))
;
// 找出小于分界值的元素的索引,并用rightIndex记录它
while (rightIndex > start
&& (data[--rightIndex].compareTo(base) >= 0))
;
// 如果i<j,交换i、j两处索引的元素
if (leftIndex < rightIndex) {
DataWrap.swap(data, leftIndex, rightIndex);
} else {
break;// 重复执行以上步骤,直到leftIndex>=rightIndex,
}
}
// 最后将分界值和rightIndex索引处的元素交换即可
DataWrap.swap(data, start, rightIndex);
// 递归左子序列
subSort(data, start, rightIndex - 1);
// 递归右子序列
subSort(data, rightIndex + 1, end);
}
}
/**
* 快速排序的时间效率很好,因为它每趟能确定的元素呈指数增长。
* 快速排序需要使用递归,而递归使用栈,因此它的空间效率为O(logN)。
* 快速排序包含跳跃式交换,因此是不稳定的排序。
*/
}
排序之前:
[21a, 30a, 49, 30b, 16, 9a, 9b, 21b]
开始进入快速排序:
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]
排序之后:
[9a, 9b, 16, 21a, 21b, 30b, 30a, 49]



Main函数:

package sort_lyf;

public class Test {
public static void main(String args[]) {
//a 代表该元素第一次出现  代表该元素第二次出现,主要是为了测试排序是否稳定
DataWrap[] data = { new DataWrap(21, "a"), new DataWrap(30, "a"),
new DataWrap(49, ""), new DataWrap(30, "b"),
new DataWrap(16, ""), new DataWrap(9, "a"),
new DataWrap(9, "b"), new DataWrap(21, "b"), };
/*
* DataWrap[] data = { new DataWrap(10, "a"), new DataWrap(9, "a"), new
* DataWrap(8, ""), new DataWrap(7, "b"), new DataWrap(6, ""), new
* DataWrap(5, "a"), new DataWrap(4, "b"), new DataWrap(3, "b"), new
* DataWrap(2, "b"), new DataWrap(1, "b")};
*/
/*
* DataWrap[] data = { new DataWrap(1, "a"), new DataWrap(2, "a"), new
* DataWrap(3, ""), new DataWrap(4, "b"), new DataWrap(5, ""), new
* DataWrap(6, "a"), new DataWrap(7, "b"), new DataWrap(8, "b"), new
* DataWrap(9, "b"), new DataWrap(10, "b")};
*/
System.out.println("排序之前:\n" + java.util.Arrays.toString(data));
/*ISort lyf = new DirectSelectSort();
lyf.sort(data);
ISort lyf = new DirectSelectSortOptimized();
lyf.sort(data);
ISort lyf = new HeapSort();
lyf.sort(data);
ISort lyf = new BubbleSortOptimized();
lyf.sort(data);*/
ISort lyf = new QuickSort();
lyf.sort(data);
System.out.println("排序之后:\n" + java.util.Arrays.toString(data));
}
}
























                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐