Java实现几种常见的排序算法

1、冒泡排序

从前往后让相邻位置的两个数字比较,这样可以把最大的或最小的放到末尾位置,如果最大的数字是在第一个位置,那么这个数字每次比较都会往后移动一位,直到末尾位置,其他数字同理。

    public void bubbleSort(int a[]) {
		int i, j, t;
		for (i = 0; i < a.length - 1; i++) {
			for (j = 0; j < a.length - 1 - i; j++) {
                                //前面的元素比后面大时交换位置,把最大的放后面
				if (a[j] > a[j + 1]) {
					t = a[j + 1];
					a[j + 1] = a[j];
					a[j] = t;
				}
			}
			
		}

	}

2、简单选择排序

 让第一个和后面所有的数字比较,这样可以先找出最小的数字放在第一个位置,然后依次找出。

    public void simpleSelectSort(int a[]) {
		int i, j, t;
		for (i = 0; i < a.length - 1; i++) {
			for (j = i + 1; j < a.length; j++) {
				if (a[i] > a[j]) {
					t = a[i];
					a[i] = a[j];
					a[j] = t;
				}
			}			
		}
	}

3、直接插入排序

以从小到大排序为例: 从第二个数字(n1)开始,从后往前和所有的数字(很明显当轮到n1时它前面的数字一定是有序的)比较,直到找到一个不大于n1的数字(n2)为止, 然后把n1插到n2的后面。

    public void insertSort(int[] a) {//
		int i, j, k;
		for (i = 1; i < a.length; i++) {
	
			int t = a[i];
			for (j = i - 1; j >= 0; j -= 1) {
				if (t < a[j]) {
					a[j + 1] = a[j];
				} else {
					break;
				}
			}
			j += 1;// 循环结束有两种情况,
					// 1、正常结束,a[i]最小此时j=-1,t应该在a[0]的位置,所以需要j+1
					// 2、a[j]不小于啊a[i],此时t应该插入a[j+1]的位置,所有需要j+1
			a[j] = t;			
		}
	}

4、希尔排序

分组进行直接插入排序。不过不是按前后位置分为n组,而是每隔n个位置的数分为一组,n一直减小,直到为1,这个时候相隔1个位置的数为一组,也就是说整个数组为一组 再进行一次插入排序。

    public void insertSort(int[] a, int q) {
		int i, j, k;
		for (i = q; i < a.length; i++) {
		
			int t = a[i];
			for (j = i - q; j >= 0; j -= q) {
				if (t < a[j]) {
					a[j + q] = a[j];
				} else {
					break;
				}
			}
			j += q;// 循环结束有两种情况,
					// 1、正常结束,a[i]最小此时j=-1,t应该在a[0]的位置,所以需要j+1
					// 2、a[j]不小于啊a[i],此时t应该插入a[j+1]的位置,所有需要j+1
			a[j] = t;			
		}
	}

	public void shellSort(int[] a) {
		int i;
		for (i = a.length / 2; i >= 1; i--) {
			insertSort(a, i);
		}
	}

5、堆排序

算法的关键就是构造大顶堆(小顶堆) 构造过程充分的利用了完全二叉树的各种性质。

        public void heapSort(int[] a) {
		int l = a.length - 1;//下标为0的位置没有用,所有长度需要-1
		/*
		 * 为什么i从l/2开始? 对完全二叉树进行编号,假设一个节点的编号是i,那么它的左右子 
                 *节点的编号一定是2i和2i+1(当然它也可能没有子节点)。
		 * 如果最后一个元素的编号是l,那么它的父节点的编号一定是l/2(取整) 在下面的循环中
                 *i是递减的,既然i是最后一个节点的父节点,
		 * 那么随着i的减少,它会包含所有节点的父节点
		 */
		for (int i = l / 2; i > 0; i--) {
			heapAdjust(a, i, l);// 先将输入的数组构造为最初的大顶堆
		}
		//printArray(a);
		for (int i = l; i > 1; i--) {
			swp(a, 1, i); // 将大顶堆的堆顶元素放到数组的最后面
			// 重新构造新的大顶堆,因为数组最后的元素已经是上个大顶堆的堆顶
			// 所有每次构造堆都可以去掉
			heapAdjust(a, 1, i - 1);
			//printArray(a);
		}
	}

	private void swp(int[] a, int i, int j) {
		int t;
		t = a[i];
		a[i] = a[j];
		a[j] = t;
	}

	public void heapAdjust(int[] a, int s, int m) {
		int temp = a[s];
		/*
		 * s为一个父节点的编号,m是此时数组的长度 i=2*s,也就是所i是s的左子节点,                
                 *i*=2,找到是下一层的左子节点
		 */
		for (int i = 2 * s; i <= m; i *= 2) {
			/*
			 * 下面的两个判断语句,是从两个子节点中找出值大的那个 然后后面和父节点        
                         *交换位置
			 */
			if (i < m && a[i] < a[i + 1]) {
				i++;
			}
			if (temp >= a[i]) {
				break;
			}

			/*
			 * 找到值大的子节点和父节点交换位置,然后更新s(空出a[i]的位置) 此时
                         * temp没有改变,仍然以它为基准,继续判断它将要去的位置的两个
			 * 子节点是否还有比它大的值,需要交换位置, 最后将temp存入空出的a[s]
                         *(s=i,a[i]位置)
			 */
			a[s] = a[i];
			s = i;
		}
		a[s] = temp;
	}

6、归并排序

将一组数据分为两组,然后再将两组数分为四组,一次类推,直到每组数组只有一个数字的时候开始合并,每次合并的时候比较大小 ,使得合并之后的数字是有序的,然后直到合并成完整的数组。

    public void mergeSort(int[] a) {
    	MSort(a, 1, a.length-1);
	}

	public void MSort(int[] a, int left, int right) {

		//条件成立时,代表每组数只有一个数字,可以开始合并了
		if(left==right) {
			return;
		}
		int center = (left + right) / 2;
		MSort(a,left,center);
		MSort(a,center+1,right);
		merge(a,left,center,right);
		//printArray(a);
	}
	
	public void merge(int[] a,int left,int center,int right) {
		//System.out.println("merge "+left+" "+center+" "+right);
		int i,j,k;
		int[] b = new int[a.length];
		/*
		 * 将两部分数组从头开始比较,小的存入新数组中,下标后移再次进行比较
		 * 合并的时候两个数组是基本有序的,所有从前往后比较就可以了
		 */
		for(i=k=left,j=center+1;i<=center&&j<=right;k++) {
			if(a[i]<a[j]) {
				b[k] =a[i];
				i++;
			} else {
				b[k]=a[j];
				j++;
			}
		}
		
		//当循环结束的时候,两个数组一定有一个没有完全存入新的数组中
		//这个时候需要将剩下的存入新的 数组中
		
		for(;i<=center;i++) {
			b[k++]=a[i];
		}
		
		for(;j<=right;j++) {
			b[k++]=a[j];
		}
		
		for(i=left;i<=right;i++) {
			a[i]=b[i];
		}
	}

7、快速排序

以最后一个元素或者第一个元素为基准,将大于基准的元素全部放到基准的后面,将小于基准的元素全部放到基准的前面,然后将基准前后两部分的元素分为两部分, 再找基准进行上面的操作,直到有序。

        public void quickSort(int[] a, int left, int right) {
		System.out.println(left+" "+right);
		if (left < right) {
			int middle = getMiddle(a, left, right);// 找出基准的位置
			quickSort(a, left, middle - 1);
			quickSort(a, middle + 1, right);
		}
	}

	public int getMiddle(int[] a, int left, int right) {

		int f = a[left];// 以每部分的第一个元素为基准,将a[left]位置空出
		// System.out.println(f+" "+left+" "+right);
		while (left < right) {
			// 小于基准的元素都应该放到基准的前面
			while (left < right && a[right] >= f) {
				right--;
			}
			// 将小于f的数字放到前面的a[left]空出的位置,这样a[right]位置就空出了
			a[left] = a[right];

			// 大于基准的元素都应该放到基准的后面
			while (left < right && a[left] <= f) {
				left++;
			}
			// 将大于f的数字放到后面的a[right]空出的位置,这样a[left]位置空出了
			// left,right是一直在变化的
			a[right] = a[left];
		}
		a[left] = f;
		return left;
	}

完整代码:

package com.wpt;

import java.util.Arrays;

public class Sort {
	/**
	 * 直接插入排序 以从小到大排序为例: 从第二个数字(n1)开始,从后往前和所有的数字(很明显当轮到n1时它前面的数字一定是有序的)比较,
	 * 直到找到一个不大于n1的数字(n2)为止, 然后把n1插到n2的后面。
	 * 
	 * @param a
	 * @return
	 */
	public void insertSort(int[] a, int q) {
		int i, j, k;
		for (i = q; i < a.length; i++) {
			//System.out.print("i=" + i + ",a[" + i + "]=" + a[i] + ": ");
			int t = a[i];

			for (j = i - q; j >= 0; j -= q) {
				if (t < a[j]) {
					a[j + q] = a[j];
				} else {

					break;
				}
			}
			j += q;// 循环结束有两种情况,
					// 1、正常结束,a[i]最小此时j=-1,t应该在a[0]的位置,所以需要j+1
					// 2、a[j]不小于啊a[i],此时t应该插入a[j+1]的位置,所有需要j+1
			a[j] = t;
			/*
			 * int flag = 0; for (j = 0; j < i; j++) { if (a[i] < a[j]) { flag = 1; break; }
			 * } int t =a[i]; if (flag == 1) { for (k = i; k >j; k--) { a[k]=a[k-1]; } a[j]
			 * = t; }
			 */

			
		}

	}

	/**
	 * 希尔排序 分组进行直接插入排序。不过不是按前后位置分为n组,而是每隔n个位置的数分为一组
	 * n一直减小,直到为1,这个时候相隔1个位置的数为一组,也就是说整个数组为一组 再进行一次插入排序
	 * 
	 * @param a
	 * @return
	 */
	public void shellSort(int[] a) {
		int i;

		for (i = a.length / 2; i >= 1; i--) {
			insertSort(a, i);
			//System.out.println();
		}
	}

	/**
	 * 简单选择排序 让第一个和后面所有的数字比较,这样可以先找出最小的数字放在第一个位置,然后依次找出
	 * 
	 * @param a
	 * @return
	 */
	public void simpleSelectSort(int a[]) {
		int i, j, t;
		for (i = 0; i < a.length - 1; i++) {
			for (j = i + 1; j < a.length; j++) {
				if (a[i] > a[j]) {
					t = a[i];
					a[i] = a[j];
					a[j] = t;
				}
			}
			
		}

	}

	/**
	 * 冒泡排序 从前往后让相邻位置的两个数字比较,这样可以把最大的或最小的放到末尾位置,
	 * 如果最大的数字是在第一个位置,那么这个数字每次比较都会往后移动一位,直到末尾位置,其他数字同理
	 * 
	 * @param a
	 * @return
	 */
	public void bubbleSort(int a[]) {
		int i, j, t;
		for (i = 0; i < a.length - 1; i++) {
			for (j = 0; j < a.length - 1 - i; j++) {
				if (a[j] > a[j + 1]) {
					t = a[j + 1];
					a[j + 1] = a[j];
					a[j] = t;
				}
			}
			
		}

	}

	/**
	 * 快速排序 以最后一个元素或者第一个元素为基准,将大于基准的元素全部放到基准的后面
	 * 将小于基准的元素全部放到基准的前面,然后将基准前后两部分的元素分为两部分, 
	 * 再找基准进行上面的操作,直到有序
	 * 
	 * @param a
	 * @param left
	 * @param right
	 */
	public void quickSort(int[] a, int left, int right) {
		System.out.println(left+" "+right);
		if (left < right) {
			int middle = getMiddle(a, left, right);// 找出基准的位置
			quickSort(a, left, middle - 1);
			quickSort(a, middle + 1, right);
		}
	}

	public int getMiddle(int[] a, int left, int right) {

		int f = a[left];// 以每部分的第一个元素为基准,将a[left]位置空出
		// System.out.println(f+" "+left+" "+right);
		while (left < right) {
			// 小于基准的元素都应该放到基准的前面
			while (left < right && a[right] >= f) {
				right--;
			}
			// 将小于f的数字放到前面的a[left]空出的位置,这样a[right]位置就空出了
			a[left] = a[right];

			// 大于基准的元素都应该放到基准的后面
			while (left < right && a[left] <= f) {
				left++;
			}
			// 将大于f的数字放到后面的a[right]空出的位置,这样a[left]位置空出了
			// left,right是一直在变化的
			a[right] = a[left];
		}
		a[left] = f;
		return left;
	}

	/**
	 * 堆排序 算法的关键就是构造大顶堆(小顶堆) 构造过程充分的利用了完全二叉树的各种性质
	 */
	public void heapSort(int[] a) {
		int l = a.length - 1;//下标为0的位置没有用,所有长度需要-1
		/*
		 * 为什么i从l/2开始? 对完全二叉树进行编号,假设一个节点的编号是i,那么它的左右子 节点的编号一定是2i和2i+1(当然它也可能没有子节点)。
		 * 如果最后一个元素的编号是l,那么它的父节点的编号一定是l/2(取整) 在下面的循环中i是递减的,既然i是最后一个节点的父节点,
		 * 那么随着i的减少,它会包含所有节点的父节点
		 */
		for (int i = l / 2; i > 0; i--) {
			heapAdjust(a, i, l);// 先将输入的数组构造为最初的大顶堆
		}
		//printArray(a);
		for (int i = l; i > 1; i--) {
			swp(a, 1, i); // 将大顶堆的堆顶元素放到数组的最后面
			// 重新构造新的大顶堆,因为数组最后的元素已经是上个大顶堆的堆顶
			// 所有每次构造堆都可以去掉
			heapAdjust(a, 1, i - 1);
			//printArray(a);
		}
	}

	private void swp(int[] a, int i, int j) {
		int t;
		t = a[i];
		a[i] = a[j];
		a[j] = t;
	}

	public void heapAdjust(int[] a, int s, int m) {
		int temp = a[s];
		/*
		 * s为一个父节点的编号,m是此时数组的长度 i=2*s,也就是所i是s的左子节点, i*=2,找到是下一层的左子节点
		 */
		for (int i = 2 * s; i <= m; i *= 2) {
			/*
			 * 下面的两个判断语句,是从两个子节点中找出值大的那个 然后后面和父节点交换位置
			 */
			if (i < m && a[i] < a[i + 1]) {
				i++;
			}
			if (temp >= a[i]) {
				break;
			}

			/*
			 * 找到值大的子节点和父节点交换位置,然后更新s(空出a[i]的位置) 此时temp没有改变,仍然以它为基准,继续判断它将要去的位置的两个
			 * 子节点是否还有比它大的值,需要交换位置, 最后将temp存入空出的a[s](s=i,a[i]位置)
			 */
			a[s] = a[i];
			s = i;
		}
		a[s] = temp;
	}

	/**
	 * 归并排序
	 * 将一组数据分为两组,然后再将两组数分为四组,一次类推,
	 * 直到每组数组只有一个数字的时候开始合并,每次合并的时候比较大小
	 * 使得合并之后的数字是有序的,然后直到合并成完整的数组
	 * @param a
	 */
	public void mergeSort(int[] a) {
		MSort(a, 1, a.length-1);
	}

	public void MSort(int[] a, int left, int right) {

		//条件成立时,代表每组数只有一个数字,可以开始合并了
		if(left==right) {
			return;
		}
		int center = (left + right) / 2;
		MSort(a,left,center);
		MSort(a,center+1,right);
		merge(a,left,center,right);
		//printArray(a);
	}
	
	public void merge(int[] a,int left,int center,int right) {
		//System.out.println("merge "+left+" "+center+" "+right);
		int i,j,k;
		int[] b = new int[a.length];
		/*
		 * 将两部分数组从头开始比较,小的存入新数组中,下标后移再次进行比较
		 * 合并的时候两个数组是基本有序的,所有从前往后比较就可以了
		 */
		for(i=k=left,j=center+1;i<=center&&j<=right;k++) {
			if(a[i]<a[j]) {
				b[k] =a[i];
				i++;
			} else {
				b[k]=a[j];
				j++;
			}
		}
		
		//当循环结束的时候,两个数组一定有一个没有完全存入新的数组中
		//这个时候需要将剩下的存入新的 数组中
		if(i<=center) {
			for(;i<=center;i++) {
				b[k++]=a[i];
			}
		}
		if(j<=right) {
			for(;j<=right;j++) {
				b[k++]=a[j];
			}
		}
		for(i=left;i<=right;i++) {
			a[i]=b[i];
		}
	}

	public void printArray(int[] a) {
		for (int i : a) {
			System.out.print(i + " ");
		}
		System.out.println();
	
		
	}
	public int[] initArray() {
		int[] a = { 10, 300, 100, 2, 4, 6, 5, 32, 1, 43, 23, 8, 7, 6, 0 };
		return a;
	}
	public static void main(String args[]) {
		Sort sort = new Sort();
		int[] a = sort.initArray();
		int l = a.length;
		System.out.println(a.length);
		// 排序前
		sort.printArray(a);
		//插入排序
		sort.insertSort(a,1);
		System.out.println("插入排序:");
		sort.printArray(a);
		//希尔排序
		a = sort.initArray();
		sort.shellSort(a);
		System.out.println("希尔排序:");
		sort.printArray(a);
		//简单选择排序
		a = sort.initArray();
		sort.simpleSelectSort(a);
		System.out.println("简单选择排序:");
		sort.printArray(a);
		//冒泡排序
		a = sort.initArray();
		sort.bubbleSort(a);
		System.out.println("冒泡排序:");
		sort.printArray(a);
		//快速排序
		a = sort.initArray();
		sort.quickSort(a,0,l-1);
		System.out.println("快速排序:");
		sort.printArray(a);
		//堆排序,可以看到堆排序,归并排序是没有用到下标为0的元素的
		a = sort.initArray();
		sort.heapSort(a);
		System.out.println("堆排序:");
		sort.printArray(a);
		//归并排序
		a = sort.initArray();
		sort.mergeSort(a);
		System.out.println("归并排序:");
		sort.printArray(a);
	}
}

可能有错误,欢迎指出。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值