数据结构——经典排序算法

排序分为内排序和外排序两种,数据结构中内排序主要排序分为4类,如下表所示:

排序名称

时间复杂度

空间复杂度

稳定性

插入排序

直接插入排序

O(n2)

O(1)

二分插入排序

O(nlogn)

O(n)

希尔排序

O(n(logn) 2)

O(1)

交换排序

冒泡排序

O(n2)

O(1)

快速排序

O(nlogn)

O(logn)

选择排序

直接选择排序

O(n2)

O(1)

堆排序

O(nlogn)

O(1)

归并排序

 

O(nlogn)

O(n)

基数排序

 

O(n+k)

O(n+k)

所需辅助空间最多:归并排序;

所需辅助空间最少:堆排序;

平均速度最快:快速排序;

不稳定的排序:希尔排序,快速排序,选择排序,堆排序

 

一、插入排序:

       (1)直接插入排序:

                思想:每次将一个待排序的数据,插入到前面已经有序的数列中的适当位置,使数列依然有序,直到待排序数据元素全部插入完毕。             

public class InsertSort{
	    /**   
	     * 排序算法的实现,对数组中指定的元素进行排序   
	     * @param a 待排序的数组   
	     * @param low 从哪里开始排序   
	     * @param high 排到哪里   
	     */ 
	public void sort(int[] a, int low, int high){
		for(int i=low+1; i<=high; i++){
			int tmp = a[i];
			int j=i;
			for(; j>low && tmp<a[j-1]; j--){    //与已有序的元素进行比较寻找插入位置
				a[j] = a[j-1];   //在比较时移动元素位置
			}
			a[j] = tmp;
		}
	}
}

       (2)二分(折半)插入排序:

                思想:每次将一个待排序的数据,插入到前面已经有序的数列中的适当位置(使用折半查找法查找插入位置),使数列依然有序,直到待排序数据元素全部插入完毕。

public class BinInsertSort {
	public void sort(int[] a, int low, int high){
		for(int i=low+1; i<high; i++){
			int lo = low, hi = i-1;
			int tmp = a[i];
			while(lo<=hi){       //折半寻找插入位置
				int mid = (lo+hi)/2;
				if(tmp < a[mid]){
					hi = mid-1;
				}else{
					lo = mid+1;
				}			
			}
			for(int j=i-1; j>hi; j--){  //移动元素
				a[j+1] = a[j];
			}
			a[hi+1] = tmp;
		}
	}
}

       (3)希尔排序:

                思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成(n除以d1)个组。所有的距离d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后取第二个增量d2<d1,重复上述分组和排序,直到所取增量dt=1,即所有记录放在同一组中进行直接插入排序为止。

public class ShellSort {
    /**   
     * 排序算法的实现,对数组中指定的元素进行排序   
     * @param a 待排序的数组   
     * @param low 从哪里开始排序   
     * @param high 排到哪里   
     * @param delta 希尔排序的步长
     */ 
	public void sort(int[] a, int low, int high, int[] delta){
		for(int k=0; k<delta.length; k++){
			partition(a, low, high, delta[k]);
		}
	}
	private void partition(int[] a, int low, int high, int delta){
		for(int i=low+delta; i<high; i++){
			if(a[i]<a[i-delta]){
				int tmp = a[i];
				int j = i-delta;
				for(; j>low&&tmp<a[j]; j=j-delta)  //在已排好的有序表中寻找插入位置
					a[j+delta] = a[j];    //在比较时移动元素位置
				a[j+delta] = tmp;
			}
		}
	}
}

二、交换排序:

       (1)冒泡排序:

                思想:每次将一个待排序的数据,插入到前面已经有序的数列中的适当位置,使数列依然有序,直到待排序数据元素全部插入完毕。     

public class BubbleSort{

    public void sort(int[] a, int low, int high){
        int n = high - low + 1;
        for(int i=low; i<n; i++){
            for(int j=i; j<high-i; j++){
                if(a[j]>a[j+1]){
                   int tmp = a[j];
                   a[j] = a[j+1];
                   a[j+1] = tmp;
                }
            }
        }
    }
}

       (2)快速排序:

              思想:在数组中任意取一数据作为基准数据,然后将所有比它小的数据放到它的前面,所有比它大的数据放到它的后面,这个过程称为一趟快速排序。然后对这两部分数据分别进行快速排序,依次递归直到所有数据有序。

public class QuickSort {
	//一次快速排序,返回基准的位置,此位置把数组分成两个部分
	private int partition(int[] r, int low, int high){
		int pivot = r[low];
		while(low<high){
			while(low<high && r[high]>=pivot) high--;
			r[low] = r[high];
			while(low<high && r[low]<=pivot) low++;
			r[high] = r[low];
		}
		r[low] = pivot;
		return low;
	}
	public void sort(int[] r, int low, int high){
		if(low<high){
			//递归进行排序
			int pa = partition(r, low, high);
			sort(r, low, pa-1);
			sort(r, pa+1, high);
		}
	}	
}

 

二、选择排序:

       (1)直接选择排序:

               思想:第一次从所有元素中选择最小的元素与R[0]交换位置,接着从剩下的R[1]...R[n]中选择最小的元素与R[1]交换位置,依次类推,直到所有元素被选择完毕。

public class SelectSort {
	public void sort(int[] a, int low, int high){
		for(int i=low; i<high-1; i++){
			int min = i;
			for(int j=i+1; j<high; j++){  //选择关键字最小的元素,返回其在数组中的位置
				if(a[min]>a[j]) min = j;
			}
			if(i!=min){        //关键字最小的元素与i位置的元素交换
				int tmp = a[i];
				a[i] = a[min];
				a[min] = tmp;
			}	
		}
	}
}

       (2)堆排序:

                堆包括大顶堆和小顶堆:根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆,又称最小堆。根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆。

               思想:将N个关键字的序列按关键字进行建堆(大顶堆或者小顶堆),输出堆顶元素,调整剩余的N-1个元素成为一个新堆,重复上述过程,直到所有元素都输出。

               初始建堆:由初始序列得到完全二叉树,按层次从上到下第一个非叶子节点开始对其调整,然后对下一个非叶子节点进行调整,直到根节点为止。

               设有M个元素的堆,输出堆顶元素后,剩下M-1个元素进行调整,输出元素后调整堆:

               首先,将堆底元素送入堆顶,此时堆被破坏,其原因是根节点不满足堆的性质,而根节点的左右子树仍然是堆;

               然后,将根结点左右子女中较大(较小)的进行交换。若与左孩子交换,则左子树谁被破坏,且仅左子树的根节点不满足堆的性质;若与右孩子交换,则与右子树交换,且仅右子树的根节点不满足堆的性质;

               继续对不满足的子树进行上述交换操作,直到叶子节点,则堆被重建。

public class HeapSort {
	private void heapAjust(int[] r, int low, int high){
		int tmp = r[low];
		for(int j=2*low; j<=high; j=j*2){  //沿关键字较大的元素向下进行筛选
			//j指向关键字较大的元素
			if(j<high&&r[j]<r[j+1]) j++;
            //若tmp比其孩子都大,则插入到low所指位置
			if(tmp>=r[j]) break;
			r[low] = r[j]; low = j;		
		}
		r[low] = tmp;
	}
	
	public void sort(int[] r){
		int n = r.length-1;
		for(int i=n/2; i>=1; i--)     //初始化建堆
			heapAjust(r, i, n);
		for(int i=n; i>1; i--){       //不断输出堆顶元素并调整r[1...i-1]为新堆
			int tmp = r[1];           //交换堆顶与堆底元素
			r[1] = r[i];
			r[i] = tmp;
			heapAjust(r,1,i-1);       //调整r[1...i-1]为新堆
		}
	}
}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值