package com.sort;
//本节学习几种常见的排序方式:
/*1.排序简介:
* 排序可以分为内部排序和外部排序,
* 2.内部排序:(只使用内存进行排序)
* 2.1插入排序:
* 直接插入排序;
* 希尔排序;
* 2.2交换排序:
* 冒泡法排序
* 快速排序
* 2.3选择排序
* 简单选择排序
* 堆排序
* 2.4 基数排序
* 2.5 归并排序
* 2.6桶排序
* ----由于对树没有一个全面的体系,在此把 2.3-2.6的内容作为下一次学习的内容---
* */
//2.1直接插入排序;
//参考文献: http://developer.51cto.com/art/201206/345156.htm
class InsertSort {
/*直接插入排序的基本思想:(从小到大)
* 把待排序的记录按其关键字的大小逐个插入到一个已经排好序的有序序列中,直到
* 所有的记录插入完成为止,得到一个新的有序序列;
* 第一步:
* 从第一个元素开始,该元素可以认为已经被排序;
* 第二步:
* 取出下一个元素,在已经排序的元素序列中 从后向前 扫描比较;
* 第三步:
* 如果该元素(已排序)大于新元素,将该元素移到下一位置
* 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 将新元素插入到该位置中
* 重复步骤2至到结束;
*
* 性能分析:
* 为了正确的插入第i个记录,最多要比较i次,最少比较1次,那么平均比较(i/2)次,总共是 从第2个到第n个数
* 所以总的比较次数:sum(i=2:n;i/2) =(n2/4)
* 空间复杂都:O(1);
* */
/**
* @param arr:要进行排序的数组
*/
public static void directInsertSort(int[] arr){
//1.拿到数组长度:
int len = arr.length;
int temp,j;
//2.外层循环遍历要进行插入的无序元素;
for(int i=1;i<len;i++){
temp = arr[i];
j = i-1;
//内部循环判断:这个无序元素与有序序列的比较,从后向前;
while(j>=0 && temp<arr[j]){
arr[j+1] = arr[j];
j--;
}
arr[j+1] = temp;
}
}
/**
* @param arr:要进行排序的数组
* @param n:要进行排序数组中的元素个数
*/
public static void directInsertSort(int[] arr,int n){
int temp, j;
//依次取出要进行排序的元素,我们默认第一个元素排好了序,因此int i =1;
for(int i=1;i<n;i++){
temp = arr[i];
//这是第二步:从后向前遍历已经排好序的元素,和这个新元素一一比较;
for(j=i-1;j>=0 && temp<arr[j];j--)
arr[j+1] = arr[j];
arr[j+1]= temp;
}
}
/*希尔排序的基本思想:
* 选定一个增量d<n,把全部记录按此值从第一个记录其进行分组,所有相距为d的记录作为一组;
* 现在各个组内进行插入排序,然后减小间隔,取第二个增量d2<d;重复上述分组和排序过程,直至
* di=1;即所有的记录放在同一组内排序;
*
* 第一步:先将元素按某个增量d分成若干组,每组中的成员是由角标相差d的元素组成的,
* 第二步:对每组中的元素进行 直接插入排序;
* 第三步:缩减d使其以一个较小的增量再进行分组,
* 第四步:重复1 2 3直到d=1;
*
* 性能分析:
* 希尔排序时间复杂都大约为 n的1.3次方;
* */
public static void shellSort(int[] arr,int n){
double d1=n;
int temp=0;
while(true){
d1= Math.ceil(d1/2); //防止出现d 等于0的时候这样程序就挂在哪里;
int d=(int) d1;
//第分成的 d 组进行各自的直接插入排序;
for(int x=0;x<d;x++){
int j;
//每组内进行直接插入排序(注意每组中的成员是角标相差d的元素组成的);
for(int i=x+d;i<n;i=i+d){
temp=arr[i];
//和本组中已经排好序的元素,进行从后向前的扫描;
for(j=i-d;j>=0 && temp<arr[j];j=j-d){
arr[j+d]=arr[j];
}
arr[j+d]=temp;
}
}
if(d==1)
break;
}
}
}
//2.交换排序
class ChangeSort{
/*1.冒泡排序的基本思想:
* 通过相邻的记录的两两比较和交换,使关键字较小的记录如同水泡一样逐步向上漂浮(数组头)
* 而关键字较大的记录好比石头一样往下沉,每一趟,都有最大的一块石头沉入水底;
* 基本思路:
* 先将一个记录的关键字和第二个记录的关键字进行比较,若为逆(左边小于右边),则交换两个记录
* 然后比较第二个记录和第三个记录,……如此下去,直到第n个和第n-1个进行比较,
* 算法实现:
* 第一步:先把最大的元素放到最后;
* 第二步:在把前 n-1个元素进行第一步操作;
* 第三步:重复 直到n=1;
*
* 性能:
* 总的时间复杂度O(n2)
*
* */
public static void bubbleSort(int[] arr,int n){
//n个元素的一组数据进行排序;
int temp;
for(int i=0;i<n;i++){
//把这组元素中 数值最大的放到最后
for(int j=0;j<n-1;j++){
if(arr[j]>arr[j+1]){
temp =arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
//让组中的元素个数减 1;
n--;
}
}
/*
* 2.快速排序
* 快速排序是对冒泡的一种改进,冒泡中记录的比较和交换是在相邻的单元中进行的;记录
* 每次交换只能上移或者下移一个单元,因而总的比较和移动次数较多,快速排序改进后,
* 让记录的比较和交换从两端向中间进行,关键字较小和较大的记录一次就能换到前面和后面;
* 基本思路:
* 在待排序的n个记录中任选一个记录,通常取第一个记录,以该记录的关键值为基准,
* 用交换的方式将所有的记录分成两部分,所有关键字比它小的记录,均排在它的之前,
* 所有关键字比它大的都排在它的后面,这样就完成了一次排序,然后对分出的两个部分
* 再进行上述排序,直到每部分只有一个记录为止,排序结束;
* 待排序记录:r[t] r[t+1] r[t+2]......r[w-1] r[w];
* 算法思路:
* 第一步:设置两个变量 i ,j ,确定第一个记录为基准记录并让i为r[t]的脚标,
* j为r[w]的脚标
* 第二步:先从j 所指示的位置向前扫描,当r[t]>r[j]时,交换r[t] 和 r[j].
* 使关键字值比基准记录的关键字值小的记录交换到前面;
* 第三步:从i所指示的位置向后扫描,直到 r[t]<r[i] 交换
* 第四步:重复上述 2,3直到i=j;为一趟排序
* */
public static void quickSort(int[] arr, int low, int high) {
int temp;
int i,j;
if(low<high){
i = low;
j= high;
temp =arr[i];
//进行一趟排序直到 i= j结束
while(i<j){
//j 向左扫描,直到找到关键字值比基准记录的值小的记录;
while(i<j && (arr[j]>=temp)){
j--;
}
//找到,则交换arr[i]和arr[j]的位置,并让 i 指向后一个元素
if(i<j){
arr[i] = arr[j];
i++;
}
//i 向右扫描,直到找到关键字值比基准记录的值大的记录;
while(i<j && arr[i]<=temp){
i++;
}
//找到,则交换arr[i]和arr[j]的位置,并让 j指向前移动一个元素
if(i<j){
arr[j] = arr[i];
j--;
}
}
arr[i] = temp;
//递归处理左区间:
quickSort(arr,low,j-1);
//递归处理右区间
quickSort(arr,j+1,high);
}
}
public static void quickSort(int[] a) {
if(a.length>0){
quickSort2(a,0,a.length-1);
}
}
private static void quickSort2(int[] a, int low, int high) {
if(low<high){
int middle = getMiddle(a,low,high);
quickSort(a, 0, middle-1);
quickSort(a, middle+1, high);
}
}
private static int getMiddle(int[] a, int low, int high) {
int temp = a[low];//基准元素
while(low<high){
//找到比基准元素小的元素位置
while(low<high && a[high]>=temp){
high--;
}
a[low] = a[high];
while(low<high && a[low]<=temp){
low++;
}
a[high] = a[low];
}
a[low] = temp;
return low;
}
}
//选择排序
/*选择排序是指每次从待排序的记录中选择出关键字值最小(最大)的记录,顺序放在已经排好
* 顺序的有序序列中,直到全部排完;
*
* */
class SelecteSort{
/*1.简单选择排序;
* 基本思想:
* 对待排序的数组,进行n-1趟扫描,第i趟扫描选出剩下的n-i+1个记录中关键字值最小的记录
* 和第i个记录交换,:
* 第一次排序空间:r[1] - r[n] 把经过比较和交换后 把最小的元素放在r[1]中,
* 第二次排序空间:r[2] - r[n] 经过选择和交换后,r[2]中放次小的记录,
* .....
*
* */
/**
* @param arr:要进行简答选择排序的数组
* @param n:数组中的前多少项元素进行排序;
*/
public static void simpleSelecteSort(int[] arr,int n){
int temp;
for(int i=0;i<n;i++){
int position = findMin(arr,i,n);
//将最小的元素和起始元素发生交换;
temp = arr[i];
arr[i] = arr[position];
arr[position] = temp;
}
}
/**
* @return :元素值最小的角标
*/
private static int findMin(int[] arr,int low,int high){
int position = low;
for(int i=low+1;i<high;i++){
if(arr[i]<arr[position])
position = i;
}
return position;
}
}
其各个函数运行结果,本人已经验证过了木有问题的;