主要介绍一下八大排序。先介绍最后上代码
一、插入排序
1、直接插入排序
简单的说,就是将一个记录插入到已经排序好了的表中,从而得到一个新的有序地表,即将第一个记录看成是一个有序地子序列,从第二个记录开始逐个进行插入,直至将整个序列排序完成。
过程如下:
2、希尔排序
希尔排序又叫做缩小增量排序。就是将整个待排序的序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录基本有序时,再去全体记录进行直接插入排序。
过程如下:
对上图进行一个详细的解读,因为n=10,所以第一次跨度是5.所以分为i以上5组,然后分别进行直接插入排序,比较的时候是if(a[i-5]<a[i])所以这五组分别交换后就得到一次排序结果。
然后第二趟时跨度时5/2=2,所以分成了以上三个组,然后再针对每一个组进行直接插入排序,得到第二次的,最后跨度是1,就是直接插入排序
二、选择排序
1、简单选择排序
就是再要排序的序列中,选出最小的或者最大的一个数与第一个位置进行交换,然后再剩下的书中在找最小或者最大的一个数与第二个位置的数进行交换。以此类推,直到第n-
个数和第n个数比较为止。
2、堆排序
(突然想要在这里多写几句),二叉树的一些性质:<1>若二叉树的层次从1开始,则再二叉树的第i层最多又2的i-1次方个结点。(i>=1)
<2>深度为k的二叉树最多有2的k次方-1个结点
<3>对任何一棵二叉树,如果其叶节点有n0个,度为2的非叶节点有n2个,则 n0=n2+1
<4>具有n个节点的完全二叉树的高度log2(n-1)的最大值-1;因为2的h次方-1<n<=2的h+1次方-1;
<5>如果将一颗有n个节点的完全二叉树自顶向下,同一层自左向右连续给编号0,1,.....n-1,则有以下关系:
- 若i=0,则i无双亲;若i>0,则i的双亲为 (i-1)/2向下取整
- 若2*i+1<n,则i的左子女为2*i+1;若2*i+2<n,则i的右子女为2*i+2
- 若i为偶数,且i!=0,则其左兄弟为i-1,若i为基数,且i!=n-1,则其右兄弟为i+1
堆排序是一种属性选择排序,是对直接选择排序的有效改进。
堆的定义如下:具有n个元素的序列,当且仅当满足:
时称之为堆。由堆的定义可以看出,堆顶元素必为最小项(小顶锥)。若以一维数组存储一个堆,则堆对应一棵完全二叉树,且所有非叶节点的值军不大于或者不小于期子女的值,根节点(堆顶元素)的值是是最小或者最大的。
如下图所示:
初始时把要排序的n个数的序列看作是一颗顺序存储的二叉树(一维数组存储二叉树),调整他们的存储顺序,使之成为一个堆,将堆顶元素输出,得到n个元素中最小或者最大的元素,这是堆的根节点的数最小或者最大,然后对前面n-1个元素重新调整使之成为对,输出堆顶元素,得到n个元素中次小或者次大的元素。以此类推,知道只有两个节点的堆,并对他们做交换,最后得到有n个节点的有序序列,成这个过程为堆排序。
所以实现堆排序需要解决两个问题:1、如何将n个待排序的数建成堆。2、输出堆顶元素后,怎样调整剩余n-1个元素,使其成为一个新堆。
要进行堆排序时,现将原始数据已续创建成完全二叉树,然后再依照下列的处理程序处理
(1)将完全二叉树转换成堆树。
(2)从数组中间位置的数据为父节点,开始调整。
(3)找出此父节点中的两个子节点中的较大者,在与父节点比较,如果父节点数据较小,则交换这两个数据。然后以交换后的子节点作为新的父节点,重复此步骤知道没有子节点为止。
(4)以步骤(3)中的原本的父节点的所在位置往前推一个位置,作为新的父节点,继续重复步骤(3)知道调到树根位置,则 堆树形成
如下图:
三、交换排序
1、冒泡排序
冒泡排序的思想比较简单。冒泡排序是一种简单的排序算法,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作室重复的进行直到没有再需要交换的,也就是该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢浮到数列的顶端
过程如下图所示:
2、快速排序
基本的思路就是:
(1)选择一个基准值,通常选择第一个或者最后一个
(2)通过一趟排序将待排序的记录分割成了两部分,其中一部分比基准值小,一部分比基准值大
(3)此时,基准值在其排好序后的正确的位置
(4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。
一趟排序的过程如下:
四、归并排序
基本的思路就是:手相肩带排序的序列分成若干个子序列,然后对每一个进行排序,然后再进行合并。。。与希尔排序类似,但是在子序列的选择上是不一样的。
实现原理如下图所示:
五、桶排序
是将阵列分到有限数量的桶子里。每个桶子再个别排序。
例如:对 6,2,4,1,5,9进行排序
准备10个空桶,最大数个空桶
6 2 4 1 5 9 待排数组
0 0 0 0 0 0 0 0 0 0 空桶
0 1 2 3 4 5 6 7 8 9 同编号 实际是不存在的
顺序从待排数组中取出数字 首先6号 然后进入6号桶 2 进入2号桶 以此类推
package 剑指offer;
import java.util.Arrays;
public class Inteview11_1 {
/**
* 一、插入排序
* @param a
* @param n
*/
//1、直接插入排序
public static void InsertSort(int a[],int n){
if(a==null||n<0||n>a.length){System.out.println("输入的数组不合法");}
if (a.length == 1) {
return;
}
for(int i=1;i<n;i++){
//判断是否比前一个数小
if(a[i]<a[i-1]){
int x=a[i];
int j;
for(j=i;j>0;j--) //遍历已经排好序的列表
{
if(a[j-1]>x){
a[j]=a[j-1]; //只要比要插入的数据大,就往后移一位
}else
break; //否则,跳出循环
}
a[j]=x; //跟前一位比,只要比前一位小,就可以插到前一位的后面,
//上面是跟j的前一位比大了所以跳出了循环,所以要插在j的位置上
}
}
System.out.println("直接插入排序:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
//2、希尔排序
public static void ShellSort(int[] a,int n) {
if(a==null||n<0||n>a.length){System.out.println("输入的数组不合法");}
if (a.length == 1) {
return;
}
for(int d=n/2;d>0;d=d/2){//首先就是对于每次d的大小的循环,循环一次结果精确一次,跨度
for(int i=0;i<d;i++){//一共有d组,第一组是0和d,第二组是1和d+1。。。。
for(int j=i+d;j<n;j=j+d)//以d为跨度进行直接插入排序
{
int k = j;
int x=a[j];
for(;k>=d ;k=k-d){
if(a[k-d]>x){
a[k]=a[k-d];
}else
break;
}
a[k]=x;
}
}
}
System.out.println("希尔排序:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
/**
* 二、选择排序
* @param a
* @param n
*/
//1、简单选择排序
public static void SampleSelectedSort(int a[],int n){
if(a==null||n<0||n>a.length){System.out.println("输入的数组不合法");}
if (a.length == 1) {
return;
}
// for(int i=0;i<n;i++){
// int k=a[i];
// for(int j=i;j<n;j++){
// if(a[j]<k)
// k=a[j];
// }
// a[i]=k;
// }
//或者
for(int i=0;i<n;i++){
int k=i;
for(int j=i;j<n;j++){
if(a[j]<a[k])
k=j;
}
int t = a[i];
a[i] = a[k];
a[k] = t;
}
System.out.println("简单选择排序:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
//2、堆排序 ,大根堆,最终输出的数组是从小到大的
public static void creatHeap(int a[],int parent,int length){
if(a==null||length<0||length>a.length){System.out.println("输入的数组不合法");}
int tmp = a[parent];
//先看他的子节点是否大于他,先取左子树
int child = parent * 2 + 1;
//一直循环到最后一个节点,就是说只要找到了一个顶点,建堆的过程可能会破坏下面已经建好的,所以需要将整个这个结点之下的所有的子树都建成堆结构
while(child < length){
//比较一下左右子树,如果这个节点存在右子树,并且右子树小于左子树
if((child+1 < length) && (a[child+1] > a[child])){
child = child + 1;
}
//开始与顶点进行比较,如果顶点小于孩子节点直接结束循环
if(tmp>a[child]){
break;
}
//否则,将父节点与子节点交换后,将父节点改成子节点的结点,继续向下筛选
int t = a[child];
a[child] = a[parent];
a[parent] = t;
parent = child;
child = parent * 2 + 1;
}
a[parent]=tmp;
}
public static void heapSort(int a[]){
//创建堆结构,从最后一个没有子节点的节点开始转换成堆结构
for(int i=a.length/2-1;i>=0;i--){
//对他进行一个建堆的过程
creatHeap(a,i,a.length);
}
//进行堆排序,即每次将顶点与最后一个结点进行调换之后重新调整堆结构
for(int i=a.length-1;i>0;i--){
int tmp = a[i];
a[i] = a[0];
a[0]=tmp;
//创建堆结构时,需要从最后一个没有子节点的节点开始,而调整的时候,每次都要直接从根结点进行调整。
creatHeap(a,0,i);
}
System.out.println("堆排序:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
/**
* 三、交换排序
* @param a
* @param n
*/
//1、冒泡排序
public static void bubbleSort(int a[],int n){
if(a==null||n<0||n>a.length){System.out.println("输入的数组不合法");}
//第一层循环控制趟数,第二成循环,遍历需要交换的元素,每完成一趟,最后一个位置的数字就会确定,下一趟就不需要再比较最后的两个
for(int i = 0;i < n-1;i++){
for(int j = 0;j < n-i-1;j++){
if(a[j] > a[j+1]){
int t = a[j];
a[j] = a[j+1];
a[j+1]=t;
}
}
}
System.out.println("冒泡排序:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
//快速排序
public static void quickSort(int a[],int low,int high){
//首先判断数组的合法性
if(a==null||low<0||high>a.length)System.out.println("输入的参数不合法");
//设置两个哨兵
int start = low;
int end = high;
//选取基准值
int x = a[low];
while(start < end){
//先从后面往前走
while(a[end] >= x&start<end)
end--;
if(a[end] < x)
{
int tmp = a[start];
a[start] = a[end];
a[end] = tmp;
}
while(a[start] <= x&&start<end)
start++;
if(a[start] > x){
int tmp = a[end];
a[end] = a[start];
a[start] = tmp;
}
}
if(start > low)quickSort(a,low,start-1);
if(end < high)quickSort(a, end+1, high);
}
/**
* 归并排序
* @param args
*/
//递归的方式
public static void MergeSort(int a[],int n){
//在排序前先建好一个长度等于n的临时数组,避免在递归的过程中频繁的开辟空间
int tmp[]=new int[n];
//然后进行归并排序,是一个分而治之的过程
Sort(a,0,n-1,tmp);
System.out.println("归并排序:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
//分
public static void Sort(int a[],int low,int high,int tmp[]){
if(low<high){
int mid = (low+high)/2;
Sort(a,low,mid,tmp);
Sort(a,mid+1,high,tmp);
Merge(a,low,mid,high,tmp);
}
}
//治
public static void Merge(int a[],int low,int mid,int high,int tmp[]){
int i=low;
int j =mid+1;
int t=0;
while(i<=mid&&j<=high){
if(a[i]>a[j]){
tmp[t++]=a[j++];
}
else{
tmp[t++]=a[i++];
}
}
while(i<=mid)
{
tmp[t++]=a[i++];
}
while(j<=high)
{
tmp[t++]=a[j++];
}
int k=0;
while(low<=high){
a[low++]=tmp[k++];
}
}
//桶排序
public static void bucketSort(int arr[],int n){
if(arr==null||n>0||n<0)System.out.println("输入的参数不合法");
int max = arr[0];
for(int i=1;i<n;i++){
if(arr[i]>max)
max=arr[i];
}
int buckets[] = new int[max];
//将待排序数组的对应的数放到桶对应的位置
for(int j=0;j<max;j++){
buckets[arr[j]]++;
}
//排序 输出
for(int i=0,j=0;i<max;i++)
{
while(buckets[i]>0)
{
buckets[i]--;
arr[j]=i;
j++;
}
}
System.out.println("桶排序:");
for(int i=0;i<arr.length;i++)
{
System.out.print(arr[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
System.out.println("原序列:");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
InsertSort(a, 16);
int b[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
ShellSort(b,16);
int c[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
SampleSelectedSort(c,16);
int d[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
heapSort(d);
int e[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
bubbleSort(e,16);
int f[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
quickSort(f,0,15);
System.out.println("快速排序:");
for(int i=0;i<f.length;i++)
{
System.out.print(f[i]+" ");
}
System.out.println();
int g[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
MergeSort(g,16);
int h[]={3,6,4,1,7,3,5,7,9,10,23,15,16,13,1,2};
bucketSort(h,16);
}
}