数据结构中的一些排序算法


冒泡排序算法

基本思想:两两相邻记录的元素,如果反序则交换!有n个元素,要比较n-1次。

//冒泡排序
	public void BubbleSort(int []a) {
		print(a,"处理前:");
		int n = a.length;
		for(int i = 0;i < n;i++) {
			for(int j = 0;j < n-1-i;j++) {
				// > 就是升序
				// < 就是降序
				if(a[j] > a[j+1]) {
					swap(j,j+1,a);
				}
			}	
		}
		print(a,"处理后:");
	}
	
	//打印数据
	private void print(int []a, String tag) {
		System.out.println(tag);
		for(int i=0;i<a.length;i++) {
			System.out.print(a[i] + " ");
		}
		System.out.println();
	}
	
	//交换数据
	private void swap(int i,int j,int[] a) {
		int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
	}

这里解释一下以上的程序,上面实现的是升序,每次的排序都是实现最大的数字往后挪,记住每次比较都是相邻的两个数比较,所以比较到最后,最后一个数就是最大的值。这里再说一遍,冒泡的思想是:两两相互比较,最大/最小的数往同一边放,这里之所以会说往同一边放,是因为你可以改变循环方向,然后就可以往数组的前面放,所以这里说往同一边放。


选择排序算法

基本思想:在后面的元素中选择最小的元素,放到数组的前面。

//选择排序
	public void SelectSort(int []a) {
		print(a,"处理前:");
		int n = a.length;
		int minIndex;
		for(int i = 0;i < n-1;i++) {
			minIndex = i;
			for(int j=i+1;j<n;j++) {
				//< 升序
				//> 降序
				if(a[j] < a[minIndex]) minIndex = j; 
			}
			if(minIndex!=i) swap(minIndex,i,a);
		}
		print(a,"处理后:");
	}

这里讲一下要领,很简单,重要的就是选择出你的数组中最大或最小的数字的index,并记下来,然后进行交换,最后完成排序。


插入排序算法

基本思想,就是将一个数据插入到已经排序好的有序表中,从而逐渐实现全部有序。

//插入排序
	public void InsertSort(int []a) {
		print(a,"处理前:");
		int n = a.length;
		int temp;
		for(int i=1;i<n;i++) {
		//< 升序
		//> 降序
			if(a[i] < a[i-1]) {
				temp = a[i];
				int j = i-1;
				// 升序 a[j] > temp
				// 降序 a[j] < temp
				while(j>=0 && a[j] > temp) {
					a[j+1] = a[j];
					j--;
				}
				a[j+1] = temp;
			}
			
		}
		print(a,"处理后:");
	}

希尔排序算法

这是插入排序的升级版,通过就是通过分组,然后在用插入排序,对插入排序实现了升级。不信我们来试试。

	//希尔排序 升序
	public void ShellSort(int []a) {
		print(a,"处理前:");
		int n = a.length;
		int temp;
		int gap = n;
		do {
			gap = gap/2;
			for(int i = gap;i<n;i++) {
				if(a[i] < a[i-gap]) {
					temp = a[i];
					int j = i-gap;
					while(j>=0 && a[j] > temp) {
						a[j+gap] = a[j];
						j-=gap;
					}
					a[j+gap] = temp;
				}
				
			}
		}while(gap > 1);
		print(a,"处理后:");
	}

看,这个希尔排序与插入排序就只差了个gap变量,而这个gap变量就是希尔排序的关键,我们通过gap来实现数据的分组排序,这就大大降低了时间的复杂度。


归并排序算法

原理:假设初始的数组有n个元素,则可以看成是n个有序的子序列,每个序列的长度都为1,然后两两归并,就是刚开始一个跟一个归并,然后两个两个归并,然后四个和四个归并依次下去,最后完成有序。
下面来看一张图你就能明白:
这里归并排序

   //归并排序 升序
	public void MergeSort(int[] a, int left, int right) {
		if (left < right) {
	        int mid = (left + right) / 2;
	        MergeSort(a, left, mid);
	        MergeSort(a, mid + 1, right);
	        merge(a, left, mid , right);
	    }
	}
	
	private void merge(int[] nums,int left,int mid, int right) {
		int []tmp=new int[nums.length];
        int p1=left,p2=mid+1,k=left;
        while(p1<=mid && p2<=right){
            if(nums[p1]<=nums[p2])
                tmp[k++]=nums[p1++];
            else
                tmp[k++]=nums[p2++];
        }
	    while (p1 <= mid) tmp[k ++] = nums[p1++];
	    while (p2 <= right) tmp[k ++] = nums[p2++];
        for (int i = left; i <=right; i++) 
        	nums[i]=tmp[i];
	}

快速排序算法

基本思想:通过找到指定一个基准点,假设是升序,这个基准点的左边都是比这个基准点小的,而右边是比这个基准点大的数,这个基准点也是影响快速排序算法的重要因素。

	//快速排序
	public void QuickSort(int[] a) {
		int n = a.length;
		quickSort(a,0,n-1);
	}
	
	private void quickSort(int[] a,int low,int high) {
		int point;
		if(low < high) {
			point = Partition(a,low,high);
			quickSort(a,low,point-1);
			quickSort(a,point+1,high);
		}
	}
	
	//找基准点
	//这也是优化这个快速排序的主要手段
	private int Partition(int[] a,int low,int high) {
		int point;
		point = a[low];
		while(low<high) {
			while(low<high && a[high] >= point) high--;
			swap(low,high,a);
			while(low<high && a[low] <= point) low++;
			swap(low,high,a);
		}
		return low;
	}

现在我们就来实现上面代码中注释中说道的优化这个基准点查找手段。现在我们来讲一下优化的几个方式,首先我们先来看这样一个数组
在这里插入图片描述可以看到这个数组是降序的,但我们的目的是实现升序吖,有小伙伴就会问了,这不也是一样的嘛,不不不!这里就不一样了,上面也说了,快速排序的方法就是找到基准点,而现在我们可以发现,经过第一轮,我们的基准点就是9,而这个基准点可谓是找的非常差了,没有把这个组分成两个部分,这就大大增加了时间复杂度。所以就有人提出了不要这么片面的选择基准点,可以采用三数取中法,意思就是取三个数之间的中间的数。下面来修改一下上面的找基准点的函数。


......
	private int Partition(int[] a,int low,int high) {
		int point;
		//三数取中间
		int mid = low + (high - low)/2;
		if(a[low] > a[high]) swap(low,high,a);
		if(a[mid] >a [high]) swap(mid,high,a);
		if(a[mid] > a[low]) swap(mid,low,a);
		point = a[low];
		while(low<high) {
			while(low<high && a[high] >= point) high--;
			swap(low,high,a);
			while(low<high && a[low] <= point) low++;
			swap(low,high,a);
		}
		return low;
	}
....

大家可以发现,上面的程序有大量的数据交换,我们也可以优化掉,改成直接赋值,下面更改代码

private int Partition(int[] a,int low,int high) {
	int point;
	//三数取中间
	int mid = low + (high - low)/2;
	if(a[low] > a[high]) swap(low,high,a);
	if(a[mid] >a [high]) swap(mid,high,a);
	if(a[mid] > a[low]) swap(mid,low,a);
	point = a[low];
	while(low<high) {
		while(low<high && a[high] >= point) high--;
		a[low] = a[high];
		while(low<high && a[low] <= point) low++;
		a[high] = a[low];
	}
	a[low] = point;
	return low;
}

PS:纯属个人理解,希望指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值