排序算法复习

先上个网络图

 分类如下

 先从基本的开始:

// 选择排序
	void selectSort(int[] arr) {
		int len = arr.length;
		int min;
		for (int i = 0; i < len - 1; i++) {
			min = i;
			for (int j = i + 1; j < len; j++) {
				if (arr[j] < arr[min]) {
					min = j;
				}
			}
			// 需要时才交换
			if (min != i) {
				swap(arr, min, i);
			}
		}
		print(arr);
	}

 

	// 冒泡排序
	void bubbleSort(int[] arr) {
		int len = arr.length;
		for (int i = 0; i < len - 1; i++) {// 最坏情况下n-1次循环
			boolean finish = true;
			for (int j = 0; j < len - i - 1; j++) {// 每次将最大的数移到右端
				if (arr[j] > arr[j + 1]) {
					swap(arr, j, j + 1);
					finish = false;
				}
			}
			if (finish)// 如果一次都不交换,说明已经完成,不需要循环到n-1次了
				break;
		}
		print(arr);
	}

 

// 插入排序
	void insertSort(int[] arr) {
		int len = arr.length;
		int j = 0;
		while (j++ < len - 1) {// 从1到n-1向前面去插
			int temp = arr[j];
			int k;
			for (k = j - 1; k >= 0; k--) {
				if (temp < arr[k])
					arr[k + 1] = arr[k];
				else
					break;
			}
			arr[k + 1] = temp;// 要么break出来,要么循环完k为-1
		}
		print(arr);
	}

 下面是快速排序,附上2个版本,一个以数组右端为基准进行分组,一个以数组首中尾元素的中值进行分组,这样可以分的更均匀些。

// 快速排序
	void fastSort(int[] arr) {
		sort(arr, 0, arr.length - 1);
		// print(arr);
	}

	int rightHead = 0;

	private void sort(int[] arr, int i, int j) {
		if (i >= j)
			return;
		rightHead = div(arr, i, j);
		sort(arr, i, rightHead - 1);
		sort(arr, rightHead + 1, j);
	}

	// 以最右端的元素作为标准,小于它的放左边,大于它的放右边
	// 返回第二个数组首端下标
	private int div(int[] arr, int i, int j) {
		int l = i - 1;
		int r = j;
		int temp = arr[j];
		while (true) {
			// 下面2个while为了寻找一对需要交换的元素
			/*
			 * while(arr[++l]<temp)//不取等号防止进行到最后继续进行,数组越界 ;
			 */
			while (l < j && arr[++l] <= temp)// 取等号,需限制一下
				;
			while (r > 0 && arr[--r] >= temp)// 可以取等号有r>0保障
				;
			if (l >= r)
				break;
			else
				swap(arr, l, r);
		}
		swap(arr, l, j);// 最后l>=r。将右端元素交换到第二个数组首端
		return l;
	}

 

// 快速排序2
	// 快速排序极不稳定,所以基准元素的选取使用首尾中三个元素的中间值
	void fastSort2(int[] arr) {
		sort2(arr, 0, arr.length - 1);
		// print(arr);
	}

	private void sort2(int[] arr, int i, int j) {

		if (j - i + 1 <= 3) {// 小于3个元素手动排序,也可以设置为其他数值
			manualSort(arr, i, j);
		} else {
			rightHead = div2(arr, i, j);
			sort2(arr, i, rightHead - 1);
			sort2(arr, rightHead + 1, j);
		}
	}

	private void manualSort(int[] arr, int i, int j) {
		if (i >= j)
			return;
		for (int k = i + 1; k <= j; k++) {
			int temp = arr[k];
			int m = k;
			while (--m >= i && temp < arr[m])
				arr[m + 1] = arr[m];
			arr[m + 1] = temp;
		}
	}

	private int div2(int[] arr, int i, int j) {
		int temp = innerSort(arr, i, j);
		int l = i;// 第1个数已然小于等于temp
		int r = j - 1;// 同理最后2个数已然大于等于temp
		while (true) {
			while (arr[++l] < temp)
				;
			while (arr[--r] > temp)
				;
			if (l >= r)
				break;
			else
				swap(arr, l, r);
		}
		swap(arr, l, j - 1);
		return l;
	}

	// 排序首中尾,并将中间数与倒数第二个元素交换,返回中间值
	private int innerSort(int[] arr, int i, int j) {
		int mid = (i + j) / 2;
		if (arr[i] > arr[mid])
			swap(arr, i, mid);
		if (arr[i] > arr[j])
			swap(arr, i, j);
		if (arr[mid] > arr[j])
			swap(arr, mid, j);
		swap(arr, mid, j - 1);
		return arr[j - 1];
	}

 下面是归并排序,思想是不断等分2组,然后2组元素逐个比较聚合成有序的1个数组

// 归并排序
	void mergeSort(int[] arr) {
		merge(arr, 0, arr.length - 1);
		print(arr);
	}

	private void merge(int[] arr, int i, int j) {
		if (i >= j)
			return;
		int mid = (i + j) / 2;
		merge(arr, i, mid);
		merge(arr, mid + 1, j);
		gather(arr, i, mid + 1, j);
	}

	private void gather(int[] arr, int f, int m, int e) {
		int n = e - f + 1;
		int[] b = new int[n];
		int low = f;
		int mid = m - 1;
		int j = 0;
		while (low <= mid && m <= e) {
			if (arr[low] <= arr[m])// 左边数组与右边数组进行比较
				b[j++] = arr[low++];
			else
				b[j++] = arr[m++];
		}
		// 左边没排完
		while (low <= mid)
			b[j++] = arr[low++];
		while (m <= e)
			b[j++] = arr[m++];
		for (int i = 0; i < n; i++)
			arr[f + i] = b[i];

	}

希尔排序:以一定的递减间隔进行插入排序,在开始的时候就可以将数组变得比较有序,后面排序工作量就少了。间隔的选择最好是质数序列。

// 希尔排序:插入排序的优化。每次都对间隔h的序列使用插入排序,间隔逐渐递减到1,就排好了
	void shellSort(int[] arr) {
		int h = 1;
		while (h <= arr.length / 3)
			h = 3 * h + 1;// 先获取一个合适的h,再原路递减回1(只要能递减回1就没问题,效率可能有差异,h序列最好是质数)
		int i, k;
		while (h > 0) {
			for (i = h; i < arr.length; i++) {
				int temp = arr[i];
				k = i;
				while (k - h >= 0 && temp < arr[k - h]) {
					arr[k] = arr[k - h];
					k = k - h;
				}
				arr[k] = temp;
			}
			h = (h - 1) / 3;
		}
		print(arr);
	}

 奇偶排序:不断交替地对奇数下标元素与其相邻元素比较交换,和对偶数下标元素同样作用。直到数组有序

// 奇偶排序,也算高效的排序,处理器可以同时进行奇偶的循环
	void oddEvenSort(int[] arr) {
		int n = arr.length;
		boolean unsorted = true;
		while (unsorted) {
			int i = 0;
			boolean b1 = evenSort(arr, i);
			i = 1;
			boolean b2 = evenSort(arr, i);
			unsorted = b1 || b2;
		}
		print(arr);
	}

	private boolean evenSort(int[] arr, int i) {
		boolean unsorted = false;
		while (i < arr.length - 1) {
			if (arr[i] > arr[i + 1]) {
				swap(arr, i, i + 1);
				unsorted = true;
			}
			i += 2;
		}
		return unsorted;
	}

基数排序:

// 基数排序/桶排序:按照个位对元素排序,然后放回数组,再对十位排序放回数组。。。
	// 如果元素最长为len,那么d为10^len
	void tankSort(int[] arr, int d) {
		int n = 1;
		int k = 0;
		int[][] array = new int[10][arr.length];// 10个桶,每个长度为数组长度
		int[] nums = new int[10];// 每个桶元素个数
		while (n < d) {
			for (int num : arr) {
				int digit = (num / n) % 10;
				array[digit][nums[digit]++] = num;
			}
			// 按个位或其他位排好一次后重新放入数组
			for (int i = 0; i < 10; i++) {
				if (nums[i] != 0) {
					for (int j = 0; j < nums[i]; j++) {
						arr[k++] = array[i][j];
					}
				}
				nums[i] = 0;// 重置为0
			}
			n *= 10;// 乘以10方便下次取更高位
			k = 0;// 和nums一样重置
		}
		print(arr);
	}

堆排序:将数组构成完全二叉树,再修改成堆即可

public class HeapSort {
	class Node {
		int data;

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

	Node[] array;
	int curSize;
	int maxSize;

	public HeapSort(int size) {
		this.curSize = 0;
		this.maxSize = size;
		array = new Node[size];
	}

	boolean insert(int data) {
		if (curSize == maxSize)
			return false;
		array[curSize] = new Node(data);
		trickleUp(curSize++);
		return true;
	}

	private void trickleUp(int index) {
		int parent = (index - 1) / 2;
		Node temp = array[index];
		while (index > 0 && temp.data > array[parent].data) {
			array[index] = array[parent];
			index = parent;
			parent = (parent - 1) / 2;
		}
		array[index] = temp;

	}

	Node remove() {
		Node temp = array[0];
		array[0] = array[--curSize];
		trickleDown(0);
		return temp;
	}

	private void trickleDown(int index) {

		int large;
		Node temp = array[index];
		while (index < curSize / 2) {// 至少一个子节点
			int left = 2 * index + 1;
			int right = left + 1;
			if (right < curSize && array[right].data > array[left].data)
				large = right;
			else
				large = left;
			if (temp.data < array[large].data) {
				array[index] = array[large];
				index = large;
			} else
				break;
		}
		array[index] = temp;

	}

	//堆排序
	void heapSort(int[] arr) {
		for (int i = 0; i < arr.length; i++)
			insert(arr[i]);
		for (int i = arr.length - 1; i >= 0; i--)
			arr[i] = remove().data;
		print(arr);
	}

	private void print(int[] arr) {
		for (int i = 0; i < arr.length; i++)
			System.out.print(arr[i] + " ");

	}

	// 堆排序,其实只需要trickleDown和remove方法
	void sort(Node[] arr) {
		array = arr;
		curSize = maxSize = arr.length;
		for (int i = 0; i < maxSize; i++)
			System.out.print(array[i].data + " ");
		System.out.println();
		for (int i = maxSize / 2 - 1; i >= 0; i--)
			trickleDown(i);//关键代码
		for (int i = maxSize - 1; i >= 0; i--)
			array[i] = remove();
		for (int i = 0; i < maxSize; i++)
			System.out.print(arr[i].data + " ");
	}

	public static void main(String[] args) {
		int size = 100;
		HeapSort hs = new HeapSort(size);
		Random rand = new Random();
		int[] arr = new int[size];
		for (int i = 0; i < size; i++)
			arr[i] = rand.nextInt(size * 5);
		hs.heapSort(arr);
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值