排序算法总结
来自瞎搞的枣儿
部分代码是我自己写的,如果道友发现错误望指出,谢谢~
排序大概可以分为内部排序和外部排序,其中内部排序主要有插入排序、冒泡排序、选择排序、归并排序、快速排序、堆排序(二叉堆)、桶排序、基数排序。外部排序主要是对较大文件的数据的处理
为什么学排序
- First, sorting algorithms illustrate many creative approaches to problem solving, and these approaches can be applied to solve other problems.
- Second, sorting algorithms are good for practicing fundamental programming techniques using selection statements, loops, methods, and arrays.
- Third, sorting algorithms are excellent examples
to demonstrate algorithm performance.
翻译:- 首先,排序算法阐明了许多解决问题的创造性的方法,并且这些方法还可以解决其他问题;
- 其次,排序算法有助于使用选择语句、循环语句、方法和数组来练习基本的程序设计技术;
- 最后,排序算法是演示算法性能几号的例子
ps.以下均为升序排序
插入排序
定义:将新元素插入到已排好序的子线性表中,直至整个表排好序
bad:
list2[0]=list1[0];
for(int i=1;i<list1.length;i++){
for(int j=0;j<i;j++){
list2[i]=list1[i];
if(list1[i]<list2[j]){
for(int k=i;k>j;) list2[k]=list2[--k];
list2[j]=list1[i];
}
}
}
good:
for(int i=1;i<list.length;i++){
int currentElement=list[i];
int k;
for(k=i-1;k>0&&lsit[k]>currentElement;k--){
list[k+1]=list[k];
}
list[k+1]=currentElement;
}
比较:多余数组,未考虑到从后向前比较并赋值
时间复杂度O( n2 )
冒泡排序(下沉排序)
定义:多次遍历数组,在每次遍历中连续比较相邻的元素,如果元素间并未按规定的顺序排列,则互换他们的位置
算法实现:
//每次遍历后,最大的数在后边,所以第N次只要比较list.length-N次
int tmp=0;
for(int i=1;i<list.length;i++0{
for(int j=0;j<list.length-i;j++){
if(list[j]>list[j+1]){
tmp=lsit[j];
list[j]=list[j+1];
list[J+1]=tmp;
}
}
}
优化版:
//如果某次遍历未发生交换则说明list中的元素已经按照规定的顺序排列好了
Boolean bo=true;//判断是否发生排序
int tmp=0;
for(int i=1;i<list.length&&bo;i++){
bo=false;
for(int j=0;j<list.length-i;j++){
if(list[j]>list[j+1]){
tmp=lsit[j];
list[j]=list[j+1];
list[J+1]=tmp;
bo=true;
}
}
}
时间复杂度: 最优情况下,只进行一次遍历,比较了N-1次,O(n);
最坏的情况下,进行了N-1次遍历,第一次比较了N-1次,第二次比较了N-2次。。。以此类推,时间为O(
n2
)
选择排序(旋转)
定义:找出最小的数和第一个元素交换,接下来在剩下的数中找到最小的数,将它和第二个元素交换,以此类推,知道数列中仅剩一个数为止
算法实现:
public static selectionSort(int[] list){
for(int i=0;i<list.length-1;i++){
int currentMin=list[i];
int currentMinIndex=i;
for(int j=i+1;j<list.length;j++){
if(currentMin>list[j]){
currentMin=list[j];
currentMinIndex=j;
}
}
if(currentMinIndex!=i){
list[currentMinIndex]=list[i];
list[i]=currentMin;
}
}
}
时间复杂度:O( n2 )
归并排序
定义:将数组分为两半,对每部分递归地应用归并排序,在两部分都排好序后,对他们进行归并
算法实现:
public static void mergeSort(int[] list){
if(list.length>1){
int[] firstHalf=new int[list.length/2];
int[] secondHalf=new int[list.length-list.length/2];
System.arraycopy(list,0,firstHalf,o,list.length/2);
System.arraycopy(list,0,scondHalf,o,list.length-list.length/2);
mergeSort(firstHalf);
mergeSort(secondHalf);
merge(firstHalf,secondHalf,list);
}
}
//归并
public static void merge(int list1,int list2,int tmp){
int current1=0;
int current2=0;
int current=0;
while(current1<list1.length&¤t2<list2.length){
if(list1[current1]<lsit2[current2])
tmp[current++]=list1[current1++];
else tmp[current++]=list2[current2++];
}
while(current1<list1.length)
tmp[current++]=list1[current1++];
while(current2<list2.length)
tmp[current++]=list2[current2++];
}
并行高效处理(待补充)
时间复杂度:O(nlogn)
ps:java.util.Arrays类中的sort方法是使用归并排序实现的
快速排序
定义:选择一个主元,将数组分成两部分,一部分大于主元,一部分小于主元,分别对两部分递归地应用快速排序算法
算法实现:
//假定第一数为主元
public static void quickSort(int[] list){
if(list.length>1){
int privot=list[0];
int m=0;
int n=0;
for(int i=1;i<list.length;i++){
if(list[i]<=privot) m++;
else n++;
}
int[] list1=new int[m];
int[] list2=new int[n];
m=n=0;
for(int i=1;i<list.length;i++){
if(list[i]<=privot) list1[m++]=list[i];
else list2[n++]=list[i];
}
quickSort(list1);
quickSort(list2);
for(int i=0;i<list.length;i++){
if(i<m) list[i]=list1[i];
else if(i>m) list[i]=list2[i-m-1];
else list[i]=privot;
}
}
}
时间复杂度:O(nlogn)
归并排序和快速排序均采用了分而治之。在最差的情况下归并排序效率高于快速排序,但在平均情况下,两者效率相同。
归并排序在归并两个子数组时需要一个临时数组,而快速排序不需要额外的数组空间,因此,快速排序的效率高于归并排序
堆排序
定义:使用的是二叉堆,它首先将所有的元素添加到一个堆上,然后不断移除最大的元素以获得一个排好序的线性表
二叉堆是一棵具有以下属性的二叉树:
1.形状属性,他是一棵完全二叉树
2.堆属性:每个结点大于或等于它的任意一个孩子
完全二叉树:如果一棵二叉树的每一层都是满的,或者最后一层可以不填满并且最后一层的叶子都是靠左放置的,那么这就是一棵完全二叉树
二叉树的存储及结点的增删(待补充)
算法实现:
public class Heap<E extends Comparable<E>>{
private java.util.ArrayList<E> list=new java.util.ArrayList<>();
//最好自己写默认的构造器
public Heap(){
}
public Heap(E[] objects){
for(int i=0;i<objects.length;i++)
add(objects[i]);
}
//增
public void add(E newObjects){
list.add(newObjects);
int curretnIndex=list.size()-1;
while(currentIndex>0){
int parentIndex=(currentIndex-1)/2;
//交换位置
if(list.get(currentIndex).compareTo(list.ger(parentIndex))>0){
E tmp=list.get(currentIndex);
list.set(currentIndex,list.get(parentIndex));
list.set(parentIndex,tmp);
}
else break;
}
}
//删根节点
public E remove(){
if(list.size()==0) return null;
E removedObject=list.get(0);
list.set(0,list.get(list.size()-1));
list.remove(list.size()-1);
int currentIndex=0;
while(currentIndex<list.size()){
int leftChildIndex=2*currentIndex+1;
int rightChildIndex=2*currentIndex+2;
if(leftChildIndex>=list.size()) break;
int maxIndex=leftChileIndex;
if(rightChileIndex<list.size()){
if(list.get(maxIndex).compareTo(list,get(rightChildIndex))<0){
maxIndex=rightChileIndex;
}
}
if(list.get(currentIndex).compareTo(lsit.get(maxIndex))<0){
E tmp=list.get(maxIndex);
list.set(maxIndex,list.get(currentIndex));
list.set(currentIndex,tmp);
}
else break;
}
return removeObject;
}
public int getSize(){
return list.size;
}
}
时间复杂度O(nlogn)
堆排序的空间效率高于归并排序
桶排序和基数排序
这两种排序均是对整数进行排序的高效算法
简单来说,桶排序就是将对应数值放入对应编号的桶中,再将数据一个个从桶中取出
为应对数值大的数据,基数排序就派上用场了,基数排序需要十个桶,每次分别按从低位到高位,按对应位上数值的大小放入桶中,进行一次排序,直至最高位,最后得到排好序的数据
外部排序
针对大型外部数据的排序