Java--排序算法

目录

 

 各种排序算法效率

1.插入排序

2.选择排序

3.冒泡排序

4.快速排序

5.希尔排序

6.折半插入排序

7.归并排序

8.二叉树排序

*************************************华丽的分割线*********************************************

9.基数排序

10.堆排序


 各种排序算法效率

各种常用排序算法

类别

排序方法

时间复杂度

空间复杂度

稳定性

复杂性

特点

最好

平均

最坏

辅助存储

 

简单

 

插入

排序

直接插入

O(N)

O(N2)

O(N2)

O(1)

稳定

简单 

 

希尔排序

O(N)

O(N1.3)

O(N2)

O(1)

不稳定

复杂

 

选择

排序

直接选择

O(N)

O(N2)

O(N2)

O(1)

不稳定

 

 

堆排序

O(N*log2N)

O(N*log2N)

O(N*log2N)

O(1)

不稳定

复杂

 

交换

排序

冒泡排序

O(N)

O(N2)

O(N2)

O(1)

稳定

简单

1、冒泡排序是一种用时间换空间的排序方法,n小时好
2、最坏情况是把顺序的排列变成逆序,或者把逆序的数列变成顺序,最差时间复杂度O(N^2)只是表示其操作次数的数量级
3、最好的情况是数据本来就有序,复杂度为O(n)

快速排序

O(N*log2N)

O(N*log2N) 

O(N2)

O(log2n)~O(n) 

不稳定

复杂

1、n大时好,快速排序比较占用内存,内存随n的增大而增大,但却是效率高不稳定的排序算法。
2、划分之后一边是一个,一边是n-1个,
这种极端情况的时间复杂度就是O(N^2)
3、最好的情况是每次都能均匀的划分序列,O(N*log2N)

归并排序

O(N*log2N) 

O(N*log2N) 

O(N*log2N) 

O(n)

稳定

复杂

1、n大时好,归并比较占用内存,内存随n的增大而增大,但却是效率高且稳定的排序算法。

基数排序

O(d(r+n))

O(d(r+n))

O(d(r+n))

O(rd+n)

稳定

复杂

 

注:r代表关键字基数,d代表长度,n代表关键字个数

1.插入排序

思想:假设前面的都是有序的,依次将后面的无序的数,插入前面有序的。

	 public static void insertSort(int[] a) {
		 int j = 0;
		 for (int i = 1; i < a.length; i++) {
			int temp = a[i];
			for (j = i-1; j >= 0 ; j--) {
				if(a[j]>temp) {//如果a[j]>temp,依次向后移动
					a[j+1] = a[j];//记录j的值就是temp要插入的地方
				}else {
					break;
				}
			}
			a[j+1] = temp;//由于j--,所以要加一
		}
	 }

2.选择排序

思路:在一组要排序的数组中,找到最小的一个与第一个交换,依次类推,直到数组中倒数第二个和第一个比较为止。

	  public static int[] sortSelect(int[] a) {
		  for (int i = 0; i < a.length; i++) {
			int temp;
			for (int j = i+1; j < a.length; j++) {
				if(a[i]>a[j]) {//如果满足条件,则交换
					temp = a[i];
					a[i] = a[j];
					a[j] = temp;
				}
			}
		}
		  return a;
	  }
/**
	 * 优化后的
	 * @param a
	 * @return
	 */
    public static int[] sortSelect(int[] a) { 
    	int temp = 0;
    	
        for (int i = 0; i < a.length; i++) {          	
            int index = i;  
            for (int j = i + 1; j < a.length; j++) {  
                if (a[j] < a[index])  //先不交换,找出最小的索引,存起来
                    index = j;  
            }  
            if (i != index)  //如果i和索引不相同,交换位置
				temp = a[i];
				a[i] = a[index];
				a[index] = temp; 
        }  
        return a;  
    } 

3.冒泡排序

思路:冒泡排序就是把小的元素往前调或者把大的元素往后调。

	public static int[] sortBubble(int[] a) {  
		int temp;
        for (int i = 1; i < a.length ; i++) {  // 外循环为排序趟数,len个数进行len-1趟 
            for (int j = 0; j < a.length - i; j++) {  //内循环为每趟比较的次数,第i趟比较len-i次
                if (a[j] > a[j + 1])  //相邻元素比较,若逆序则交换(升序为左大于右,降序反之)
                {
                	temp = a[j];
                	a[j] = a[j+1];
                	a[j+1] = temp;
                }
                    
                
            }  
        }  
        return a;  
    }

4.快速排序

思路:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,

将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其

排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

public static void quickSort(int[] a,int low,int high) {
		int i,j,temp,t;
		if(low>high) {
			return; //如果low>high,退出调用
		}
		i = low; 
		j = high;
		temp = a[low];//将第一个数作为基准数
		
		while(i<j) {
			//从右往左,大于基准数,依次减一
			while(temp<=a[j]&&i<j) {
				j--;
			}
			//从左往右,小于基准数,依次加一
			while(temp>=a[i]&&i<j) {
				i++;
			}
			//如果满足条件,则交换
			if(i<j) {
				t = a[j];
				a[j] = a[i];
				a[i] = t;
			}
		}
        //最后将基准为与i和j相等位置的数字交换
		a[low] = a[i];
		a[i] = temp;
	
		quickSort(a, low, j-1);	//递归调用左半数组
		quickSort(a, j+1, high);//递归调用右左半数组
	}

5.希尔排序

思路:首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高

详解:https://blog.csdn.net/qq_39207948/article/details/80006224

public static void shellSort(int[] a) {
		int N = a.length;
		//进行分组,最开始的增量(gap)为数组长度的一半
		for (int gap = N/2; gap > 0; gap /=2) {
			//对各个分组进行插入排序
			for (int i = gap; i < N; i++) {
				int temp = a[i];
				int j;
				for (j = i-1; j >= 0 ; j--) {
					if(a[j]>temp) {//如果a[j]>temp,依次向后移动
						a[j+1] = a[j];//记录j的值就是temp要插入的地方
					}else {
						break;
					}
				}
				a[j+1] = temp;//由于j--,所以要加一
			}
		}
	}
public class ShellSort {

	public static void main(String[] args) {
		int[] a = {2,1,4,7,9,6,8,0};
		int N = a.length;
		for(int gap=N/2;gap>0;gap--) {
			InsertSort(a, gap);
		}
		System.out.println(Arrays.toString(a));
	}
	
	public static void InsertSort(int a[],int gap) {
		for(int i=gap;i<a.length;i++) {
			int temp = a[i];
			int j;
			for(j=i-1; j >= 0 ; j--) {
				if(temp<a[j]) {
					a[j+1] = a[j];
				}else {
					break;
				}
			}
			a[j+1] = temp;
		}
	}
}

******************************************************华丽的分割线*****************************************************************

6.折半插入排序

原理:二分法寻找插入顺序,插入排序插入数据。

public static int[] binSearchSort(int[] a){
		
		int n  = a.length;
		int i,j;
		for (i = 1; i < n; i++) {//插入排序,遍历序列,从第二个开始
			int temp = a[i];
			int left = 0;
			int right = i-1;
			while(left<=right) {    //二分查找选择插入位置
				int mid = (left+right)/2;				
				if(a[mid]>temp) {
					right = mid-1;
				}else {
					left = mid+1;
				}
			}
			
			for(j = i-1;j>=left;j--)
				a[j+1] = a[j];//腾出插入位置
			a[j+1] = temp;//赋值
			}
		return a;
	}

7.归并排序

基本思路:将数组分解成A,B两个数组,假设A,B两个数组都是有序的,那么将这两个数组比较排序就好了,假设有一个数组为空,那么把剩下的那个数组拿过来放到后面就行了。那么怎么才能使这个数组有序那,继续将这两个数组递归,递归到数组中只有一个元素时,这时数组就有序了,然后我们再把相邻的数组合并,这个数组就变成有序数组了。

思路我们说完了,那么我们先来解决第一个问题,相邻数组的合并。

	void MemeryArray(int[] a,int n,int[] b,int m,int[] c) {
		
		int i=0,j=0,k=0;
		
		while(i<n&&j<m) {//合并两个相邻数组
			if(a[i]<b[j]) {
				c[k++] = a[i++];
			}else {
				c[k++] = b[j++];
			}
		}
		while(i<n) {//如果b数组空,直接将a数组拿到c数组中
			c[k++] = a[i++];
		}
		while(j<m) {//如果a数组空,直接将b数组拿到c数组中
			c[k++] = b[j++];
		}
	}

解决了数组的合并,那接下来的重点就是将数组递归分割成一个一个的小数组了。

	static void memger(int[] a,int l,int r,int[] t) {		
		if(l<r) {//递归分割成含有一个元素的数组,然后在合并
			int m = (l+r)/2;			
			memger(a, l, m,t);//分割左数组
			memger(a, m+1, r,t);//分割右数组
			mergerArray(a,l,m,r,t);//合并数组
		}
	}

接下来只要在修改一下我们的合并数组的方法就可以了,很简单,只要加一个for循环赋值就可以了。

	static void mergerArray(int[] a,int l,int m,int r,int[] temp){
		int i = l,j = m+1;
		int k = 0;
		while(i<=m&&j<=r) {
			if(a[i]<=a[j]) {
				temp[k++] = a[i++];
			}else {
				temp[k++] = a[j++];
			}
		}
		while(i<=m) {
			temp[k++] = a[i++];
		}
		while(j<=r) {
			temp[k++] = a[j++];
		}
		for (i = 0; i < k; i++) 
			a[l + i] = temp[i];	//递归的过程中,l有可能不为0
	}
	

测试用例

	public static void main(String[] args) {
		int[] test = {9,2,6,3,5,7,10,11,12};
		int[] temp = new int[test.length];
		memger(test,0,test.length-1,temp);
		for (int i = 0; i < temp.length; i++) {
			int j = test[i];
			System.out.print(j+",");
		}
	}

8.二叉树排序

原理:构造树的过程就是排序的过程,在构造过程中,比根小的是左子树,比根大的是右子树。所以中序遍历就是有序的序列

package cn.datastruct.tree;

public class BinTreeSort {

	private static Node root;

	class Node {

		private int val;
		private Node lTree;
		private Node rTree;

		public Node(int val) {
			this.val = val;
		}

	}

	public boolean addNode(int val) { //建立二叉树
		Node node = new Node(val);  
		if (root == null) {
			root = node;
			return true;
		} else {
			Node cur = root;
			while (true) {
				if (cur.val > val) {
					if(cur.lTree==null) {
						Node newNode = new Node(val);//新建准备赋给左子树的结点
						cur.lTree = newNode;
						return true;
					}
					cur = cur.lTree;
				} else {
					if (cur.val < val) {
						if(cur.rTree==null) {
							Node newNode = new Node(val);//新建准备赋给右子树的结点
							cur.rTree = newNode;
							return true;
						}						
						cur = cur.rTree;
					} else {
						return false;//不允许重复
					}
				}
			}
		}
	}
	/**
	 * 中序
	 * @param node
	 */
	public void inOrder(Node node) {
		if(node==null) {
			return;
		}
		inOrder(node.lTree);
		System.out.println(node.val);
		inOrder(node.rTree);
	}
	
	public static void main(String[] args) {
		BinTreeSort tree = new BinTreeSort();
		int[] a = new int[] { 3, 1, 0, 2, 7, 5, 8, 9 };
		for (int i : a) {
			tree.addNode(i);
		}
		tree.inOrder(root);
	}
}

*************************************华丽的分割线*********************************************
 

9.基数排序

 

10.堆排序

去TM的。。。。。。。。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值