不多说,直接上干货!

插入排序包括直接插入排序、希尔排序

1、直接插入排序:

如何写成代码:

  首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用插入。

  设定插入数和得到已经排好序列的最后一个数的位数。insertNum和j=i-1。

  从最后一个数开始向前循环,如果插入数小于当前数,就将当前数向后移动一位。

  将当前数放置到空着的位置,即j+1。

代码实现如下:

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class InsertSortDirectly {
public static void insertSort(int[] a){
int length = a.length; //求取出length是为了提高速度
int insertNum ;
for(int i=;i<length;i++){//要插入的数
insertNum = a[i];
int j = i-;
while(j>=&&insertNum<a[j]){
a[j+] = a[j];
j--;
}
//比如3 6 5,此时找到j为3,则在j+1的位置插入5。
a[j+]=insertNum;
}
} public static void main(String[] args) {
int[] a= {,,};
insertSort(a);
System.out.println(Arrays.toString(a));
}
}

  直接插入排序,最好的情况是数据元素已经全部排好序,那么内循环次数为0,外循环次数为n-1,所以,最好的情况下时间复杂度为O(N)。最坏的情况是原始数据元素集合反序排列,此时,算法中内层while循环的循环次数每次均为i。因此,最坏的情况下时间复杂度为O(N^2)。直接插入排序的空间复杂度为O(1),显然直接插入排序是一种稳定的排序算法。

 2、希尔排序:

          

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class SheelSort {
public static void SheelSort(int[] a){
int d = a.length;
while(d!=){
d = d/;
for(int x = ; x < d; x++){//分的组数
for(int i=x+d; i<a.length; i=i+d){//组中的元素,从第2个开始
int j = i-d; //j为有序序列最后一位的位数
int temp = a[i]; //要插入的元素
for(; j>=&&temp<a[j]; j=j-d){
a[j+d] = a[j];//向后移动d位
}
a[j+d] = temp;
}
}
}
} public static void main(String[] args) {
int[] a ={,,,,,,,,,};
SheelSort(a);
System.out.println(Arrays.toString(a));
}
}

  希尔排序虽然用了四重循环,但是其实前两层的循环次数很少,后两层就是直接插入排序,由于希尔排序小组内数据基本有序,因此内部的直接插入排序很快就排好。所以,希尔排序的时间复杂度为O(nlbn),空间复杂度为O(1),由于希尔排序算法是按增量分组进行的排序,所以,希尔排序是一种不稳定的排序算法。如5,1,1,5,如果采用步长为2,则两个1相对位置进行了交换。

 选择排序包括直接选择排序堆排序。

3、直接选择排序

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class SelectSortDirectly {
public static void selectSort(int[] a){
int len = a.length;
int minIndex,temp;
for(int i=;i<len-;i++){
minIndex = i;
for(int j=i+;j<len;j++){
if(a[j]<a[minIndex]){
minIndex = j;
}
}
temp = a[i];
a[i] = a[minIndex];
a[minIndex] = temp;
}
} public static void main(String[] args) {
int[] a ={,,,,,,,,,};
selectSort(a);
System.out.println(Arrays.toString(a));
}
}

  直接选择排序的时间复杂度是O(N^2),空间复杂度是O(1),它是一种不稳定的排序算法。比如2 2 2 1,这样选出最小数1和第一个2交换,那么2的相对位置发生了改变。如果在选出最小记录后,将它前面的无序记录依次后移,然后再将最小记录放在有序区的后面,这样就能保证排序算法的稳定性。

4、堆排序

  对简单选择排序的优化。

  将序列构建成大顶堆。

  将根节点与最后一个节点交换,然后断开最后一个节点。

  重复第一、二步,直到所有节点断开。

  堆排序关键要理解,从下往上,调整节点,比如说,这棵树一共3层,那么将第2层的树作为根节点,保证它的子节点都小于它,此时,如果调整第1层,若其左节点是最大值,必然会将第一层根节点和左节点进行交换,以保证第1层满足最大堆的结构,但此时,有可能会破坏第1层的左节点的最大堆结构,因此需要对这个第1层的左节点的堆进行重新调整。-------------这是关键要理解的地方!

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class HeapSort {
public HeapSort(){
} public static void heapSort(int[] a){
System.out.println("开始排序");
int arrayLength=a.length;
//循环建堆
for(int i=;i<arrayLength-;i++){
//建堆
buildMaxHeap(a,arrayLength--i);
//交换堆顶和最后一个元素
swap(a,,arrayLength--i);
}
} private static void swap(int[] data, int i, int j) {
//TODO Auto-generated method stub
int tmp=data[i];
data[i]=data[j];
data[j]=tmp;
} //对data数组从0到lastIndex建大顶堆
private static void buildMaxHeap(int[] data, int lastIndex) {
//从lastIndex处节点(最后一个节点)的父节点开始 for(int i=(lastIndex-)/;i>=;i--){
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while(k*+<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=*k+;
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if(biggerIndex<lastIndex){
//若果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
} //如果k节点的值小于其较大的子节点的值
if(data[k]<data[biggerIndex]){
//交换他们
swap(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
//如果不理解,那么请使用打断点的方式来运行,则可发现,当i=0时,由于节点1和节点0发生了交换,因此需要重新调整1节点的堆结构,保证
//1节点的值仍然大于其左右节点的值
k=biggerIndex;
}else{
break;
}
}
}
} public static void main(String[] args) {
int a[] = {,,,,,,};
heapSort(a);
System.out.println(Arrays.toString(a));
}
}

  堆排序算法是基于完全二叉树的排序,其时间复杂度是O(nlbn),其空间复杂度是O(1),堆排序是一种不稳定的排序算法,比如5 5 5,这样,构建好最大堆后,第1个5和最后一个5要进行交换,因此,堆排序是一种不稳定的排序算法。

  利用交换数据元素的位置进行排序的方法是交换排序。常用的交换排序有冒泡排序和快速排序。快速排序是一种分区交换排序方法。

5、冒泡排序

  将序列中所有元素两两比较,将最大的放在最后面。

  将剩余序列中所有元素两两比较,将最大的放在最后面。

  重复第二步,直到只剩下一个数。

如何写成代码:

  设置循环次数。

  设置开始比较的位数,和结束的位数。

  两两比较,将最小的放到前面去。

  重复2、3步,直到循环次数完毕。

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class BubbleSort {
public static void bubbleSort(int[] a){
boolean isSorted = true;
for(int i=;i<a.length-&&isSorted;i++){
isSorted = false;
for(int j=;j<a.length--i;j++){
if(a[j]>a[j+]){
int temp = a[j];
a[j] = a[j+];
a[j+] = temp;
isSorted = true;//内循环如果发生了交换,则证明还在继续排序
}
}
//如果经过1趟就已经排序完毕,那么第2趟结束后,isSorted = false; ,此时,
//外循环可以根据isSorted的标记状态提前结束。
}
} public static void main(String[] args) {
int[] a ={,,,,,,,,,};
bubbleSort(a);
System.out.println(Arrays.toString(a));
}
}

  冒泡排序的时间复杂度是O(n^2),空间复杂度为O(1),冒泡排序是一种稳定的排序算法。

快速排序是一种二叉树结构的交换排序方法。

6、快速排序

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class QuickSort {
/**
* 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
*
* @param numbers 带查找数组
* @param low 开始位置
* @param high 结束位置
* @return 中轴所在位置
*/
public static int getMiddle(int[] numbers, int low,int high){
int temp = numbers[low]; //数组的第一个作为中轴
while(low < high){
while(low < high && numbers[high] > temp){
high--;
}
if(low<high){
numbers[low++] = numbers[high];//强制塞值并向前移一位
}
while(low < high && numbers[low] < temp){
low++;
}
if(low<high){
numbers[high--] = numbers[low] ; //强制塞值并向前移一位
}
}
numbers[low] = temp ; //中轴记录到尾
return low ; // 返回中轴的位置
} /**
*
* @param numbers 带排序数组
* @param low 开始位置
* @param high 结束位置
*/
public static void quickSort(int[] numbers,int low,int high){
if(low < high){
int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
quickSort(numbers, low, middle-); //对低字段表进行递归排序
quickSort(numbers, middle+, high); //对高字段表进行递归排序
}
} /**
* 快速排序
* @param numbers 带排序数组
*/
public static void quick(int[] numbers){
if(numbers.length > ){ //查看数组是否为空{
quickSort(numbers, , numbers.length-);
}
} public static void main(String[] args) {
int a[] = {,,,,,};
quick(a);
System.out.println(Arrays.toString(a));
}
}

  快速排序如果每次选取的标准元素都能均分两个子数组区间长度,这样的快速排序过程是一个完全二叉树结构。最好情况下快速排序算法时间复杂度是O(nlbn)。快速排序最坏的情况是,数据元素已经全部有序,此时数组根节点的分解次数构成一颗二叉退化树,所以,最坏情况下快速排序算法的时间复杂度是O(n^2)。

  由于快速排序算法需要堆栈空间临时保存递归调用参数,堆栈空间的使用个数和递归调用的次数有关,由于二叉树有可能是单支二叉树,而单支二叉树的深度为n-1,所以,最坏情况下快速排序算法的空间复杂度是O(n)。

 7、归并排序

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class MergeSort {
/**
* 归并排序
* 简介:将两个(或两个以上)有序表合并成一个新的有序表 即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列
* 时间复杂度为O(nlogn)
* 稳定排序方式
* @param nums 待排序数组
* @return 输出有序数组
*/
public static int[] sort(int[] nums, int low, int high) {
int mid = (low + high) / ;
if (low < high) {
//左边
sort(nums, low, mid);
//右边
sort(nums, mid + , high);
//左右归并
merge(nums, low, mid, high);
}
return nums;
} public static void merge(int[] nums, int low, int mid, int high) {
int[] temp = new int[high - low + ];
int i = low;// 左指针
int j = mid + ;// 右指针
int k = ; //把较小的数先移到新数组中
while (i <= mid && j <= high) {
if (nums[i] < nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
} //把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = nums[i++];
} //把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = nums[j++];
} //把新数组中的数覆盖nums数组
for (int k2 = ; k2 < temp.length; k2++) {
nums[k2 + low] = temp[k2];
}
} //归并排序的实现
public static void main(String[] args) {
int[] nums = { , , , , , , , , , };
MergeSort.sort(nums, , nums.length-);
System.out.println(Arrays.toString(nums));
}
}

  归并排序的时间复杂度是O(nlbn),由于归并排序使用了n个临时内存单元存放数据元素,所以,归并排序算法的空间复杂度是O(n)。

  归并排序是一种稳定的排序算法。前面的几个时间复杂度是O(nlbn)的排序算法都是不稳定的排序算法,而归并排序算法不仅时间复杂度是O(nlbn),而且还是一种稳定的排序算法。这是归并排序算法的最大特点。

8、基数排序

  基数排序,因为要求进出桶中的数据元素要满足先入先出的原则,因此,这里所说的桶其实就是队列。

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

/*
* 对于一个int数组,请编写一个基数排序算法,对数组元素排序。
* 给定一个int数组A及数组的大小n,请返回排序后的数组。保证元素均小于等于2000。
*
测试样例:
[1,2,3,5,2,3],6
[1,2,2,3,3,5]
*/ public class RadisSort {
//各位装通法
public static int[] radixSort(int[] A, int n) {
//首先确定排序的趟数;
int max=A[];
for(int i=;i<n;i++){
if(A[i]>max){
max=A[i];
}
}
int time=;
//判断位数;
while(max>){
max/=;
time++;
}
int length = n;
int divisor = ;// 定义每一轮的除数,1,10,100...
int[][] bucket = new int[][length];// 定义了10个桶,以防每一位都一样全部放入一个桶中
int[] count = new int[];// 统计每个桶中实际存放的元素个数
int digit;// 获取元素中对应位上的数字,即装入那个桶
for (int i = ; i <= time; i++) {// 经过4次装通操作,排序完成
for (int temp : A) {// 计算入桶
digit = (temp / divisor) % ;
bucket[digit][count[digit]++] = temp;
}
int k = ;// 被排序数组的下标
for (int b = ; b < ; b++) {// 从0到9号桶按照顺序取出
if (count[b] == )// 如果这个桶中没有元素放入,那么跳过
continue;
for (int w = ; w < count[b]; w++) {
A[k++] = bucket[b][w];
}
count[b] = ;// 桶中的元素已经全部取出,计数器归零
}
divisor *= ;
}
return A;
} public static void main(String[] args) {
int a[] = {,,,,,};
System.out.println(Arrays.toString(radixSort(a, a.length)));
}
}

  基数排序时间复杂度是O(mn),m是数字的最大位数,由于基数排序算法中要m次使用n个节点临时存放n个数据元素,因此,基数排序算法的空间复杂度为O(n)。

基数排序是一种稳定的排序算法。

总结:

  排序分内部排序和外部排序两种。内部排序是指把待排数据元素全部调入内存中进行的排序。如果数据元素的数量太大,需要分批导入内存中。分批导入内存的数据元素排好序后再分批导出到磁盘的排序方法称作外部排序。两者排序算法原理很大地方都相同,但是内存中的读写速度和在外存的读写速度差别很大,所以评价标准差别很大。这里只讨论内部排序。

排序算法优劣的标准:

  1、时间复杂度。

  2、空间复杂度:算法中使用的辅助存储空间是多少。当排序算法中使用的辅助存储空间与要排序数据元素的个数n无关时,其空间复杂度为O(1)。

  3、稳定性。

各种排序算法性能比较:

  排序方法                             最好时间                    平均时间               最坏时间                       最坏辅助空间                      稳定性

  直接插入排序                       O(n)                         O(n^2)               O(n^2)                         O(1)                                 稳定

  希尔排序                             O(nlbn)                     O(nlbn)              O(nlbn)                         O(1)                                不稳定

  直接选择排序                      O(n^2)                      O(n^2)              O(n^2)                         O(1)                                不稳定

  堆排序                               O(nlbn)                      O(nlbn)              O(nlbn)                         O(1)                               不稳定

  冒泡排序                            O(n)                           O(n^2)              O(n^2)                         O(1)                                 稳定

  快速排序                            O(nlbn)                      O(nlbn)              O(n^2)                         O(n)                               不稳定

  归并排序                            O(nlbn)                      O(nlbn)              O(nlbn)                         O(n)                                 稳定

  基数排序                            O(mn)                       O(mn)                 O(mn)                          O(n)                                 稳定

牛客网Java刷题知识点之插入排序(直接插入排序和希尔排序)、选择排序(直接选择排序和堆排序)、冒泡排序、快速排序、归并排序和基数排序(博主推荐)的更多相关文章

  1. 牛客网Java刷题知识点之为什么HashMap和HashSet区别

    不多说,直接上干货! HashMap  和  HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的 ...

  2. 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?

    不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...

  3. 牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap

    不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...

  4. 牛客网Java刷题知识点之ArrayList 、LinkedList 、Vector 的底层实现和区别

    不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...

  5. 牛客网Java刷题知识点之垃圾回收算法过程、哪些内存需要回收、被标记需要清除对象的自我救赎、对象将根据存活的时间被分为:年轻代、年老代(Old Generation)、永久代、垃圾回收器的分类

    不多说,直接上干货! 首先,大家要搞清楚,java里的内存是怎么分配的.详细见 牛客网Java刷题知识点之内存的划分(寄存器.本地方法区.方法区.栈内存和堆内存) 哪些内存需要回收 其实,一般是对堆内 ...

  6. 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  7. 牛客网Java刷题知识点之UDP协议是否支持HTTP和HTTPS协议?为什么?TCP协议支持吗?

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  8. 牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤

    福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑         Java全栈大联盟   ...

  9. 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合

    不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...

  10. 牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现

    不多说,直接上干货! 先来看个泛型概念提出的背景的例子. GenericDemo.java package zhouls.bigdata.DataFeatureSelection; import ja ...

随机推荐

  1. ETL之Tungsten Replicator

    1 概述 1.1 介绍 Tungsten Replicator是数据库集群和复制供应商Continuent推出的高性能.开源的数据复制引擎,是Continuent最先进的集群解决方案的核心组件之一,特 ...

  2. 三、kafka主要配置

      1.Broker配置 <ignore_js_op>      2.Consumer主要配置 <ignore_js_op>  3.Producer主要配置 <ignor ...

  3. tomcat部署虚拟主机-搭建两个应用以及httpd和Nginx的反向代理

    实验环境:CentOS7 前提:已经安装好tomcat,未安装请查看http://www.cnblogs.com/wzhuo/p/7111135.html: 目的:基于主机名访问两个应用: [root ...

  4. linux日常管理-free查看内存工具

    查看内存 命令 free  默认是k为单位 也可以指定 m为单位 或者G为单位,这个不精准 total 总容量 used  使用了多少 free  剩余多少 看第二行.第一行是物理内存,加上虚拟内存b ...

  5. Java接口定义和实现

    1. 使用interface来定义一个接口.接口定义类似类的定义,分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成.定义接口的基本格式如下: [修饰符] interface 接口名 [ ...

  6. 一个自动修改本地IP地址的BAT

    set /a num1=%random%%%200+1+1  //生成随机数set ip=192.168.1.//ip 主体set ip1=%ip%%num1% //拼接两部分cmd /c netsh ...

  7. 关于Android阻塞的解决方法

    首先新建一个线程,然后有两种方法 1.POST方法(直接,但是可读性差) 2.使用AnycTask类,可读性好,而且是POST方法的封装

  8. zookeeper-3.4.5-cdh5.1.0 完全分布式安装

    1.环境 主机名 IP地址 JDK ZooKeeper myid c1 192.168.58.129 1.7.0_11 server.1 1 c2 192.168.58.130 1.7.0_11 se ...

  9. 阶段3-团队合作\项目-网络安全传输系统\sprint1-传输子系统设计\第3课-加密传输优化

    对之前的传输系统进行加密,使之成为加密的网络传输系统 客户端编程模型 通过以上模型对传统的TCP传输模型进行优化 首先完成初始化工作,它是要在创建socket之前完成 主要是以上四个函数的实现,那么这 ...

  10. 6.5 Ubuntu中安装搜狗输入法

    传统的方式:http://www.cnblogs.com/zlslch/p/6943318.html 最简单的方式: