1.选择排序
对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换,接着对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换,重复,直到进行比较的记录只有一个时为止
eg:{38,65,97,76,13,27,49}
第一趟13 [65 97 76 38 27 49]
第二趟13 27 [97 76 38 65 49]
第三趟13 27 38 [76 97 65 49]
第四趟13 27 38 49 [97 65 76]
第五趟13 27 38 49 65 [97 76]
第六趟13 27 38 49 65 76 [97]
最终 13 27 38 49 65 76 97
2.插入排序
初始时假设第一个记录自成一个有序序列,其余记录为无序序列
从第二个记录开始,按照记录的大小依次将当前处理的记录插入到之前的有序序列中
直到最后一个记录插入到有序序列中为止
eg:{38,65,97,76,13,27,49}
第一步插入38 [38] 65 97 76 13 27 49
第二步插入65 [38 65] 97 76 13 27 49
第三步插入97 [38 65 97] 76 13 27 49
第四步插入76 [38 65 76 97] 13 27 49
第五步插入13 [13 38 65 76 97] 27 49
第六步插入27 [13 27 38 65 76 97] 49
第七步插入49 [13 27 38 49 65 76 97]
3.冒泡
单项冒泡,从小到大
从第一个记录开始依次对相邻的两个记录进行比较
当前面的记录大于后面的记录时,交换位置
进行一轮比较和换位后,n个记录中的最大值将位于第n位
然后对前n-1个记录进行第二轮比较
重复该过程直到进行比较的记录只剩下一个为止
eg:{36,25,48,12,25,65,43,57}
1趟排序[25 36 12 25 48 43 57 65]
2趟排序[25 12 25 36 43 48] 57 65
3趟排序[12 25 25 36 43] 48 57 65
4趟排序[12 25 25 36] 43 48 57 65
5趟排序[12 25 25] 36 43 48 57 65
6趟排序[12 25] 25 36 43 48 57 65
7趟排序[12] 25 25 36 43 48 57 65
package sort;
public class TestSort {
/*
* 选择排序
* 对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换
* 接着对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换
* 重复,直到进行比较的记录只有一个时为止
*/
public static void selectSort(int[] a){
int temp=0;
int flag=0;
int n=a.length;
for(int i=0;i<n;i++){
temp=a[i];
flag=i;
for(int j=i+1;j<n;j++){
if(a[j]<temp){
temp=a[j];
flag=j;
}
}
if(flag!=i){
a[flag]=a[i];
a[i]=temp;
}
}
}
/*
* 插入排序
* 初始时假设第一个记录自成一个有序序列,其余记录为无序序列
* 从第二个记录开始,按照记录的大小依次将当前处理的记录插入到之前的有序序列中
* 直到最后一个记录插入到有序序列中为止
*/
public static void insertSort(int [] a){
if(a!=null){
for(int i=1;i<a.length;i++){//从第一个起进行每一次的比较
int temp=a[i];
int j=i;
if(a[j-1]>temp){
while(j>=1&&a[j-1]>temp){//将下一个和前面排序好的,从最大处依次比较,找到合适的位置记录
a[j]=a[j-1];
j--;
}
}
a[j]=temp;//插入到记录的位置
}
}
}
/*
* 单项冒泡,从小到大
* 从第一个记录开始依次对相邻的两个记录进行比较
* 当前面的记录大于后面的记录时,交换位置
* 进行一轮比较和换位后,n个记录中的最大值将位于第n位
* 然后对前n-1个记录进行第二轮比较
* 重复该过程直到进行比较的记录只剩下一个为止
*/
public static void BubbleSort(int [] a){//从后开始排,排n趟
int temp;
for(int i=0;i<a.length-1;i++){
for(int j=a.length-1;j>i;j--){
if(a[j]<a[j-1]){
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
}
}
}
}
public static void bubbleSort(int [] a){//从前开始排
int temp=0;
int size=a.length;
for(int i=0;i<size-1;i++){
// for(int k:a){//测试,输出每一趟排序后的结果
// System.out.print(k+" ");
// }
// System.out.println();
for(int j=0;j<size-1-i;j++){
if(a[j]>a[j+1]){
temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
}
public static void main(String [] args){
int a[]={38,65,97,76,13,27,49};
// selectSort(a);
// insertSort(a);
BubbleSort(a);
for(int i:a){
System.out.print(i+" ");
}
System.out.println();
}
}
4.希尔排序
先将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少
然后对各个子序列分别进行直接插入排序
等待整个待排序序列基本有序后,最后对所有元素进行一次直接插入排序
eg:{26,53,67,48,57,13,48,32,60,50}
选定的步长序列为{5,3,1}
第一趟:[13 48 32 48 50 26 53 67 60 57]
第二趟:[13 48 26 48 50 32 53 67 60 57]
第三趟:[13 26 32 48 48 50 53 57 60 67]
public class ShellSort {
public static void shellSort(int [] array){
int length=array.length;
int i,j,h;
int temp;
for(h=length/2;h>0;h=h/2){
for(i=h;i<length;i++){
temp=array[i];
for(j=i-h;j>=0;j=j-h){
if(temp<array[j]){
array[j+h]=array[j];
}
else{
break;
}
}
array[j+h]=temp;
}
}
}
public static void main(String []args){
int a[]={49,38,65,97,76,13,27};
shellSort(a);
for(int i:a){
System.out.print(i+" ");
}
}
}
5.归并排序
利用递归与分治技术将数据序列划分为越来越小的半子表,再对半字表排序,最后再用递归方法将排好序的半字表合并成越来越大的有序序列
对于给定的一组记录n,首先将每两个相邻的长度为1的子序列进行归并,得到n/2(向上取整)个长度为1或2的有序子序列,再将其两两归并,反复执行此过程,直到得到一个有序序列
public class MergeSort {
public static void mergeSort(int array[],int low,int high){
if(low<high){
int mid=(low+high)/2;
//二路归并里面有两个mergeSort,多路归并里面写多个
mergeSort(array,low,mid);//左边
mergeSort(array,mid+1,high);//右边
merge(array,low,mid,high);//左右归并
}
}
public static void merge(int [] array, int low, int mid, int high){
int [] temp=new int[high-low+1];
int i=low;//左指针
int j=mid+1;//右指针
int k=0;
while(i<=mid&&j<=high){//把较小的先移到新数组中
if(array[i]<array[j]){
temp[k++]=array[i++];
}
else{
temp[k++]=array[j++];
}
}
while(i<=mid){//左边剩余的移入数组
temp[k++]=array[i++];
}
while(j<=high){//右边剩余的移入数组
temp[k++]=array[j++];
}
for(int k2=0;k2<temp.length;k2++){//把新数组中的数覆盖array数组
array[k2+low]=temp[k2];
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[]={5,4,9,8,7,6,0,1,3,2};
int len=a.length;
mergeSort(a,0,len-1);
for(int i=0;i<len;i++){
System.out.print(a[i]+" ");
}
}
}
二路归并排序的过程需要进行logn趟,每一趟归并排序的操作,就是将两个有序子序列进行归并,而每一对有序子序列归并时,记录的比较次数均小于等于记录的移动次数,记录移动的次数均等于文件中记录的个数n,即每一趟归并的时间复杂度为O(n),因此二路归并的时间复杂度为O(nlogn)
6.快速排序
通过一趟排序将待记录分割成独立两部分,一部分记录的关键字均比另一部分小
把整个序列看做一个数组,第0个位置看做中轴(基准关键字),和最后一个比,如果比他小交换,比他大不做任何处理
交换后再和小的那端比,比他小不交换,比他大交换
循环一趟排序完成,左边就是比中轴小,右边比中轴大
再采用分治,分别对这两个独立的数组进行排序
public class QuickSort {
public static void sort(int [] array,int low, int high){
int i,j,index;
if(low>=high){
return;
}
i=low;
j=high;
index=array[i];//第一个作为中轴
while(i<j){
while(i<j&&array[j]>=index){
j--;
}
if(i<j){
array[i++]=array[j];//比中轴小的记录移到低端
}
while(i<j&&array[i]<index){
i++;
}
if(i<j){
array[j--]=array[i];//比中轴大的记录移到高端
}
}
array[i]=index;//中轴记录到尾
sort(array,low,i-1);
sort(array,i+1,high);
}
public static void quickSort(int array[]){
sort(array,0,array.length-1);
}
public static void main(String []args){
int a[]={49,38,65,97,76,13,27};
quickSort(a);
for(int i:a){
System.out.print(i+" ");
}
}
}
基准关键字的选取:是决定快排算法性能的关键
(1)三者取中:指在当前序列中,将其首、尾和中间位置上的记录进行比较,选择三者的中值作为基准关键字,在划分开始前交换序列中的第一个记录与基准关键字的位置
(2)取随机数:取left和right之间的一个随机数m(left<=m<=right)
时间复杂度
(1)最好:指每次区间划分的结果都是基准关键字左右两边的序列长度相等或相差为1,即选择的基准关键字为待排序的记录中的中间值,此时进行比较的次数总共为nlogn
(2)最坏:指每次区间划分的结果都是基准关键字的左边或者右边序列为空,而另一边区间中的记录项仅比排序前少了一项,即选择的基准关键字是待排序的所有记录中最小或者最大的,该情况下时间复杂度为O(n*n)
(3)平均:O(nlogn)
7.堆排序
7.1堆结构
堆结构是一个树结构,准确说是一个完全二叉树,在这个树中每个结点对应于原始数据的一个记录,并且每个结点应满足:
如果按照从小到大的顺序排序,要求非叶结点的数据要大于或等于其左、右子结点的数据;如果按照从大到小的顺序排序,要求非叶结点的数据要小于或等于其左、右子结点的数据
7.2堆排序过程
一个完整的堆排序需要经过两个步骤:构造堆结构和堆排序输出。
构造堆结构就是把原始无序数据按照前面的堆结构的定义进行调整,首先,将原始无序数据放置到一个完全二叉树的各个结点中;然后,由完全二叉树的下层向上层逐层对父子结点的数据进行比较,使父节点的数据大于子节点的数据。这里需要使用“筛”运算进行结点数据的调整,直到所有结点最后满足堆结构的条件为止。
(代码还没看太懂,先贴上来)
public class HeapSort {
public static void adjustMinHeap(int [] a,int pos,int len){
int temp;
int child;
for(temp=a[pos];2*pos+1<=len;pos=child){
child=2*pos+1;
if(child<len&&a[child]>a[child+1]){
child++;
}
if(a[child]<temp){
a[pos]=a[child];
}
else{
break;
}
}
a[pos]=temp;
}
public static void myMinHeapSort(int [] array){
int i;
int len=array.length;
for(i=len/2-1;i>=0;i--){
adjustMinHeap(array,i,len-1);
}
for(i=len-1;i>=0;i--){
int tmp=array[0];
array[0]=array[i];
array[i]=tmp;
adjustMinHeap(array,0,i-1);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int i=0;
int a[]={5,4,9,8,7,6,0,1,3,2};
int len=a.length;
myMinHeapSort(a);
for(i=0;i<len;i++){
System.out.print(a[i]+" ");
}
}
}
总结:性能分析
所有相等的数经过某种排序后,仍能保持它们在排序之前的相对次序,就称这种排序方法时稳定的,反之是非稳定的,eg:一组数据在排序之前是a1,a2,a3,a4,a5其中a2=a4,经过某种排序后,a1,a2,a4,a3,a5,则这种排序是稳定的,因为a2排序前在a4前面,排序后还在a4前面。