学习笔记,一些常用排序算法。
2017-04-16 01:59
302 查看
冒泡排序
时间复杂度O(n^2)
排序的思想:从头开始将目标数挨个与后面的数比较一次,这样在经历一次循环后,最小的数(或最大的数,看条件)就会出现在顶部;经历N次后,就会变成完全有序的数列。
优点:简单稳定,空间复杂度较低
缺点:效率不高,时间复杂度太高(因为传统的冒泡排序都是不管是不是已经排好序了,都要经历固定的次数,因为没有判断之前交换后是不是已经成为有序数列)
之前逛CSDN的时候看到冒泡排序的优化在这里也记录一下:
优化的思想就是如果已经完成排序了那么就不会再进行循环。
设置一个标志位可以帮助我们解决这个问题。
用这一次循环来判断之前上一次交换后是不是成为有序列,如果是,那么后面循环次数将不会进入循环。
选择排序
时间复杂度O(n^2)
之前一直把选择排序和冒泡排序搞混。。其实比较的两个数是不同的。
排序思想:先依次比较,选择一列中最小的数放在最开头;然后循环此过程,将剩下最小的数放在第二位、第三位。。。
插入排序
时间复杂度O(n^2)
插入排序思想:将将要排序的数字依次和前面的数列比较,然后插入其中。
快速排序
时间复杂度是O(nlogn)
排序的思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。
理解:用要排一个有N个数的正序数组举例,从第0个数做标志位开始,第一步:用第0个数和第N个数做比较,如果大于第N个数,则将第0个数和第N个数交换位置;(反之,则不交换,与N-1个数做比较;此时讨论交换的情况)
第二步:然后用第N个数和第2个数比较,如果小于第2个数,则交换;(这时比较的关系是标志位小于比较数(说明比较数大于标志位数应该在放在后面)交换而大于不交换,因为目的是将标志位前方的数全换为小于标志位的数,而后方全换为大于标志位的数)
第三步:循环第一步和第二步;
快排就是一个挖坑做标志位然后一一比较然后分治的过程
归并排序
时间复杂度O(N*logN)
排序的思想是:将数列分为最小的单元,然后对单元排序,接着合并相邻的单元然后再排序单元,递归一层接着一层返回…最后完成排序。
堆排序
时间复杂度O(N*logN)
排序的思想:最核心的就是大根堆的构建和维护,首先将要排序的数列构造成大根堆,然后利用大根堆堆顶是最大的这个特性,将堆顶挑出来依次放在数列的后面,每次挑出来后重新维护新的大根堆,使堆顶最大,然后重复。
时间复杂度O(n^2)
排序的思想:从头开始将目标数挨个与后面的数比较一次,这样在经历一次循环后,最小的数(或最大的数,看条件)就会出现在顶部;经历N次后,就会变成完全有序的数列。
优点:简单稳定,空间复杂度较低
缺点:效率不高,时间复杂度太高(因为传统的冒泡排序都是不管是不是已经排好序了,都要经历固定的次数,因为没有判断之前交换后是不是已经成为有序数列)
//java class Maopao{ public static void main(String[]args){ int[] arry={2,3,4,7,8,1,5}; int temp=0; //传统的冒泡 for(int i=0;i<arry.length;i++){ for(int j=0;j<arry.length-1;j++){ if(arry[j]<arry[j+1]){ temp=arry[j+1]; arry[j+1]=arry[j]; arry[j]=temp; } } } } }
之前逛CSDN的时候看到冒泡排序的优化在这里也记录一下:
优化的思想就是如果已经完成排序了那么就不会再进行循环。
设置一个标志位可以帮助我们解决这个问题。
用这一次循环来判断之前上一次交换后是不是成为有序列,如果是,那么后面循环次数将不会进入循环。
class Maopao{ public static void main(String[]args){ int[] arry={2,3,4,7,8,1,5}; int temp=0; boolean float=true; //利用标志位来判断 for(int i=0;i<arry.length&&float==true;i++){ float 4000 =false;//如果上次循环交换了位置就会进入这里,那么在这里设置标志位。如果这次没有交换,那么就会是0不会进入下次循环 for(int j=0;j<arry.length-1;j++){ if(arry[j]<arry[j+1]){ temp=arry[j+1]; arry[j+1]=arry[j]; arry[i]=temp; float=true;//如果交换了位置标志位就为1,表示交换了位置并没有排好序,下次仍要再来判断 } } } } }
选择排序
时间复杂度O(n^2)
之前一直把选择排序和冒泡排序搞混。。其实比较的两个数是不同的。
排序思想:先依次比较,选择一列中最小的数放在最开头;然后循环此过程,将剩下最小的数放在第二位、第三位。。。
//传入排序的数组和数组的长度n public class SelectionSort { public int[] selectionSort(int[] A, int n) { int temp=0; for(int i=0;i<n-1;i++){ for(int j=i+1;j<n;j++){ if(A[j]<A[i]){ temp=A[j]; A[j]=A[i]; A[i]=temp; } } } return A; } }
插入排序
时间复杂度O(n^2)
插入排序思想:将将要排序的数字依次和前面的数列比较,然后插入其中。
//传入排序的数组和数组的长度n public class InsertionSort { public int[] insertionSort(int[] A, int n) { int temp=0; for(int i=0;i<n-1;i++){ for(int j=i;j>=0;j--){ if(A[j]<A[j+1]){ break; } temp=A[j]; A[j]=A[j+1]; A[j+1]=temp; } } return A; }
快速排序
时间复杂度是O(nlogn)
排序的思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。
理解:用要排一个有N个数的正序数组举例,从第0个数做标志位开始,第一步:用第0个数和第N个数做比较,如果大于第N个数,则将第0个数和第N个数交换位置;(反之,则不交换,与N-1个数做比较;此时讨论交换的情况)
第二步:然后用第N个数和第2个数比较,如果小于第2个数,则交换;(这时比较的关系是标志位小于比较数(说明比较数大于标志位数应该在放在后面)交换而大于不交换,因为目的是将标志位前方的数全换为小于标志位的数,而后方全换为大于标志位的数)
第三步:循环第一步和第二步;
快排就是一个挖坑做标志位然后一一比较然后分治的过程
public class quickSort { public static void Quick(int[] array, int low, int high) { //这个判断必不可少,在递归时做结束用,也就是当最后low=high时,排序只剩一个数的时候,结束方法,层层返回 if (low < high) { //为了不改变low、high的值我新声明了变量 int i = low; int j = high; //设置标志位,把标志位的数保存起来 int temp = array[i]; while (i < j) { //从低位比较高位,要将小的换到前面去,如果相等或大于标志位,则不交换,高位减一继续比较 while (i < j && array[j] >= temp) { j--; } //高位小于标志位,进行交换 array[i] = array[j]; //交换后从高位比较低位,要讲大的换到后面去,如果相等或者小于标志位,则不交换,低位加一继续比较 while (i < j && array[i] <= temp) { i++; } //低位大于标志位,进行交换 array[j] = array[i]; } //一次排序结束,高低位相等,将标志位填入“坑”中 array[i] = temp; //递归调用,进行排序两边的数列 Quick(array, low, i-1); Quick(array, i+1, high); } } public static void main(String[] args) { int[] array = { 23, 34, 1, 46, 51, 11, 78, 15, 6, 99 }; Quick(array, 0, 9); for (int i = 0; i < array.length; i++) { System.out.print(array[i] + " "); } } }
归并排序
时间复杂度O(N*logN)
排序的思想是:将数列分为最小的单元,然后对单元排序,接着合并相邻的单元然后再排序单元,递归一层接着一层返回…最后完成排序。
public class MergeSort { public int[] mergeSort(int[] A, int n) { sort(A,0,n-1); return A; } public void sort(int[] data,int left,int right){ if(left<right){ int mid=(left+right)/2; //划分左右 sort(data,left,mid); sort(data,mid+1,right); //合并左右 merge(data,left,mid,right); } } //合并左右两个子数组 public void merge(int[] data,int left,int mid,int right){ int[] tempArray=new int[right-left+1]; //左右以及临时游标 int leftindex=left; int rightindex=mid+1; int tempindex=0; //最左的数开始和中间数比较,从中间数右边的数开始向右比较,如果两个都不越界 while(leftindex<=mid&&rightindex<=right){ //比较大小,存值 if(data[leftindex]<data[rightindex]){ tempArray[tempindex++]=data[leftindex++]; }else{ tempArray[tempindex++]=data[rightindex++]; } } //当有一边越界了,直接放入另一边的值,这说明这边的全小于另一边 while(leftindex<=mid){ tempArray[tempindex++]=data[leftindex++]; } while(rightindex<=right){ tempArray[tempindex++]=data[rightindex++]; } //将临时数组放回原数组相应位置 int temp=0; //从原数组从left开始,复制数组从0开始 while((temp+left)<=right){ data[left+temp]=tempArray[temp]; temp++; } } }
堆排序
时间复杂度O(N*logN)
排序的思想:最核心的就是大根堆的构建和维护,首先将要排序的数列构造成大根堆,然后利用大根堆堆顶是最大的这个特性,将堆顶挑出来依次放在数列的后面,每次挑出来后重新维护新的大根堆,使堆顶最大,然后重复。
public class HeapSort { public static void main(String[] args) { int[] A={4,1,3,2,16,9,10,14,8,7}; heapSort(A); for(int i:A){ System.out.print(i+" "); } } //堆排序就是利大根堆一步一步渐进排序 public static void heapSort(int[] A) { buildMaxHeap(A); int heapsize = A.length; int temp; //把堆顶放在数组后面,然后重新维护大顶堆 for (int i =heapsize-1;i >0; i--) { temp = A[0]; A[0] = A[i]; A[i] = temp; heapsize--; preserveMaxHeap(A, 0, heapsize); } } /************************** * 以下是构建大根堆的过程 * ***************************/ //返回位置为i的节点的左孩子的位置 public static int findLeftChild(int i) { return 2 * i; } //返回位置为i的节点的右孩子的位置 public static int findRightChild(int i) { return 2 * i + 1; } //返回位置为i的节点的父结点的位置 public static int findParent(int i) { if (i % 2 == 1) { return i / 2; } return i / 2 - 1; } public static void buildMaxHeap(int[] A) { int heapsize = A.length; for (int i = (A.length / 2); i >= 0; i--) { preserveMaxHeap(A, i, heapsize); } } public static void preserveMaxHeap(int[] A, int i, int heapsize) { //声明变量,用来保存左右孩子的值 int left = findLeftChild(i); int right = findRightChild(i); //声明变量max,保存比较后较大的数,用用作堆顶 int max, temp; if (left < heapsize && A[left] > A[i]) { max = left; } else { max = i; } if (right < heapsize && A[right] > A[max]) { max = right; } if (max != i) { temp = A[i]; A[i] = A[max]; A[max] = temp; //递归调用维护子树的大根堆结构 preserveMaxHeap(A, max, heapsize); } } } //输出:1 2 3 4 7 8 9 10 14 16
相关文章推荐
- 一些常用的算法笔记(烂笔头,不断学习、搜集更新...)
- Linux之ubuntu学习笔记(二):一些常用快捷键和相关命令来控制系统任务ctr+z,ctr+c,ctrl+d
- 写得蛮好的linux学习笔记(二)(一些常用的基本命令)
- 我的学习笔记(SQL简单的注入)(1) 手工注入以及注入一些常用语句
- Java学习笔记----一些常用却不清楚的知识
- [学习笔记] 自己根据一些资料整理的pb常用事件
- XNA 学习笔记(1.基础 : 常用的一些属性)
- Python学习笔记——一些常用函数、常见错误总结
- 学习笔记:adb的一些常用指令
- 多线程学习笔记六-------------线程的消亡以及一些常用方法的介绍
- bootsrap3的学习笔记,一些常用的类名
- 学习macos常用的一些快捷键笔记
- MFC学习笔记9 常用一些类
- springboot学习笔记-2 一些常用的配置以及整合mybatis
- 【Java学习笔记之十一】Java中常用的8大排序算法详解总结
- ROS学习笔记(四):ROS 的一些常用命令行功能
- 写得蛮好的linux学习笔记(一些常用的基本命令)
- LifeRay Portal 6学习笔记8:Liferay的一些常用工具类
- wss3 sdk学习笔记三:一些常用代码
- Zookeeper学习笔记一:分布式一致性的一些基本概念