几种排序算法

冒泡排序  时间复杂度o(n^2)

定义对数组的一趟排序为,顺序遍历数组,如果数组中a[i]>a[i+1],那么就交换两个数的位置(前提这是升序排序),那么一趟排序就会找到一个最大值,并且将最大值放在数组的最后。

通过对数组的一趟排序,找出一个最大的值,放在数据最后的位置,通过对数组的下一趟排序,找出数组的第二大的数字放在倒数第二个位置,那么对数组进行多趟这样的排序,就能让整个数组编程有序的。如果数组有5个数,那么四趟排序就可以,四趟排序找到四个最大的数,剩下最小的就ok,那么对于数组长度为n数组,排序n-1躺趟就ok

private static void bubbleSort(int[] arr) {
	int n=arr.length;
	for(int i=0;i<n-1;i++){
		for(int j=1;j<n-i;j++){
			if(arr[j-1]>arr[j]){
				int temp=arr[j];
				arr[j]=arr[j-1];
				arr[j-1]=temp;
				
			}
		}
	}

}

选择排序  时间复杂度o(n^2)

每一趟排序选择出来一个最小的放在前面,多趟排序之后序列就会成有序的。同样还是n-1躺排序就可以了

private static void selectSort(int[] arr) {
	int n=arr.length;
	for(int i=0;i<n-1;i++){
		int k=i;//假设每一趟排序的第一个数就是那个最小的
		for(int j=i+1;j<n;j++){
			if(arr[j]<arr[k]){
				k=j;
				
			}
		}
		if(k>i){
			int temp=arr[k];
			arr[k]=arr[i];
			arr[i]=temp;
		}
	}
}


堆排序  时间复杂度o(nlogn)

堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。分为最大堆和最小堆,最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点。所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小), 且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。

我个人人为堆排序的虽然效率上真的不错,但是这个堆的创建有点啰嗦,并不是很简洁 ,同时快速排序的效率不比堆排序差,但是相比堆排序来说更简洁,用快速排序就ok了

public  void myHeapSort(int array[])
    {
        BuildHeap(array);
        for(int i=array.length-1;i>=0;i--)
        {	//把堆顶元素移到数组的后面。
            int temp=array[0];
            array[0]=array[i];
            array[i]=temp;
  
            heapify(array,0,i);
        }
    }
	
    public  void BuildHeap(int arr[]){
        for(int i=0;i<arr.length;i++)
        {//使用插入堆的方法从上往下进行建堆
        	int parent=(i-1)/2;
            while(parent>=0&&arr[i]<arr[parent])
            {
            //如果父节点的下标大于0、并且当前节点小于父节点交换位置。继续向上比较,否则停止比较。
                if(i==0)
                    break;
                int temp=arr[parent];
                arr[parent]=arr[i];
                arr[i]=temp;
                i=parent;
                parent=(i-1)/2;
            }  
         }
    }
    public void heapify(int arr[],int i,int len)
    {       //调整堆,因为堆排序的时候我们都是选择堆顶元素,
            //所以调整的时候都是从堆顶向下调整,因此此时的i始终是0
        int l=2*i+1;
        int r=2*i+2;
        int lestgest=i;
        //用于保存最小节点的下标
        while(l<len)
        {
            if(arr[l]<arr[lestgest])
            {
                lestgest=l;
            }
            if(r<len&&arr[r]<arr[lestgest])
            {
                lestgest=r;
            }
             if(i==lestgest)
                break;
            int temp=arr[i];
            arr[i]=arr[lestgest];           
            arr[lestgest]=temp;
           
            i=lestgest;
            l=2*i+1;
            r=2*i+2;
        }
    }


快速排序  时间复杂度o(nlogn)

在快速排序中,我们先要选择一个基准,用作一趟排序中交换的标准,在一趟排序中,从左到右要有一个指针start,从右到左还要有一个指针end,从左到右找比基准大的数,然后和end位置进行交换,从右到左找比基准小的数,然后和start位置进行交换。当start和end重合在一起那么这趟排序结束,当前位置就是这个数组的分界点,左边的都是小于当前值,右边的都是大于当前值,然后递归操作两边,直到排序结束。

public void sort(int[] a,int low,int high){
         int start = low;
         int end = high;
         int key = a[low];
         
         
         while(end>start){
             //从后往前比较
             while(end>start&&a[end]>=key)  //如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
                 end--;
             if(a[end]<=key){
                 int temp = a[end];
                 a[end] = a[start];
                 a[start] = temp;
             }
             //从前往后比较
             while(end>start&&a[start]<=key)//如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置
                start++;
             if(a[start]>=key){
                 int temp = a[start];
                 a[start] = a[end];
                 a[end] = temp;
             }
         //此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用
         }
         //递归
         if(start>low) sort(a,low,start-1);//左边序列。第一个索引位置到关键值索引-1
         if(end<high) sort(a,end+1,high);//右边序列。从关键值索引+1到最后一个
     }
     
}


归并排序  时间复杂度o(nlogn)




public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if(low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            //左右归并
            merge(a,low,mid,high);
        }
        return a;
    }
     
    public static void merge(int[] a, 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(a[i]<a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组 
        while(i<=mid){
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while(j<=high){
            temp[k++] = a[j++];
        }
        // 把新数组中的数覆盖nums数组
        for(int x=0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }
























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值