2018.7.13学习笔记二——常用排序算法及实现(未完)

7 篇文章 0 订阅
排序方法最优时间平均时间最差时间辅助空间稳定性
冒泡O(n)O(n^2)O(n^2) 稳定
插入O(n)O(n^2)O(n^2) 稳定
选择O(n^2)O(n^2)O(n^2) 不稳定
希尔 O(n^1.25)  不稳定
O(nlgn)O(nlgn)O(nlgn) 不稳定
快速O(nlgn)O(nlgn)O(nlgn) 不稳定
归并O(nlgn)O(nlgn)O(nlgn)O(n)稳定

认为排序到从小到大有序,推荐一个网站,排序可视化:https://visualgo.net/en/sorting

交换:

public void exch(Comparable[] a, int i, int j)
{
	Comparable temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

冒泡排序:从第一个开始,比较相邻元素,比右边大则交换位置,知道最大元素排到最后一个位置,反复此过程

public void bubbleSort(Comparable[] a)
{
	if (a == null)
		return;
	for (int i = 0; i < a.length; i++)
	{
		for (int j = 1; j < a.length - i; j++)	// 控制冒泡范围
		{
			if (a[j].compareTo(a[j-1]) < 0)		// 如果a[j] < a[j-1],交换两者位置
			{
				
			}
		}
	}
}

插入排序:从第一个元素开始,认为第一个元素有序,然后第二元素插入前面的有序子数组,插入过程为前面的子数组的最后一个开始与之比较,知道插入合适的位置,再第三个,第四个,。。。,直到结束

public void insertSort(Comparable[] a)
{
	if (a == null)
		return;
	for (int i = 1; i < a.length; i++)
	{
		for (int j = i; j >= 0 && a[j].compareTo(a[j-1]) < 0; j--)
		{
                        exch(a, j, j-1);
		}
	}
}

选择排序:从第一个元素开始,与后面每个元素比较,找到最小元素,然后交换第一个元素与最小元素位置,在从第二个开始。反复这个过程

public void selectSort(Comparable[] a)
{
	if (a == null)
		return;
	for (int i = 0; i < a.length; i++)
	{
		int min = i;
		for (int j = i + 1; j < a.length; j++)
		{
			if (a[j].compareTo(a[min]) < 0)
				min = j;
		}
		exch(a, min, i);
	}
}

希尔排序:使得数组中任意间隔为h的元素都是有序的,确定初始h的值,再逐步缩小h的值

public void hillSort(Comparable[] a)
{
	if (a == null)
		return;
	int N = a.length;
	int h = 1;
	while (h < N/3)
		h = 3 * h + 1;
	while (h >= 1)
	{
		for (int i = h; i < N; i++)
			for (int j = i; j >= h; j -= h)
				if (a[j].compareTo(a[j-h]) < 0)
					exch(a, j, j-h);
		h /= 3;
	}
}

堆排序:堆的构造(堆有序)+ 下沉排序

堆的定义:1)堆有序:当一颗二叉树的每个节点均大于等于它的两个子节点

                 2)根节点是堆有序的二叉树中的最大节点

                3)堆的特点,假设存储在数组中,数组长度为N,则使用数组a[N+1],a[0]不放数值。父节点位置为k,则子节点位置为2k和2k+1,子节点位置为k,父节点位置为k/2

下沉操作:

private void sink(Comparable[] a, int k, int N)
{	// N表示数组长度
	while (2 * k <= N)
	{
		int j = 2 * k;
		if (j < N && a[j].compareTo(a[j+1]) < 0)	// 找到较大的那个子节点
			j++;
		if (a[k].compareTo(a[j]) >= 0)	// 直到父节点不再小于子节点的值,终止循环
			break;
		exch(a, k, j);		// 交换子节点与父节点的位置
		k = j;
	}
}

堆的构造: 令k=N/2(找到最后一点的父节点),从此节点开始,直到k=1,执行下沉操作,达到堆有序的状态

for (int k = N / 2; k >= 1; k--)
        sink(a, k, N);

下沉排序:堆有序中,最大元素必定在根节点

while (N > 1)
{
	exch(a, 1, N--);
	sink(a, 1, N);
}

堆排序:

public void heapSort(Comparable[] a)
{
	if (a == null)
		return;
	int N = a.length;
	Comparable[] aCopy = new Comparable[N+1];
	for (int i = 1; i < N+1; i++)
		aCopy[i] = a[i-1];	// 使得a[0]~a[N-1] 变成 a[1]~a[N]
	// 构造有序堆
	for (int k = N / 2; k >= 1; k--)
		sink(aCopy, k, N);
	// 下沉排序
	while (N > 1)
	{
		exch(aCopy, 1, N--);
		sink(aCopy, 1, N);
	}
	for (int i = 0; i < N; i++)
		a[i] = aCopy[i+1];	// 使得a[1]~a[N] 变成 a[0]~a[N-1]
}

快速排序:一种“分治”的排序算法,递归发生在处理数组(切分)之后

标准快速排序:取a[lo](数组第一个元素)作为切分匀速,从数组左边开始扫描找到一个大于等于a[lo]的元素,从数组右端开始扫描找到一个小于等于a[lo]的元素,两则交换位置。反复执行得到a[lo]...a[j]...a[],交换a[lo]与a[j]的位置,使得a[lo](现在在第j位置)左边元素全部小于等于它,右边元素全部大于等于它,再对左右两个子数组(递归)用相同方式处理。

性能特点:简洁,比较次数少,切分不平衡时低效

public void quickSort(Comparable[] a)
{
	quickSort(a, 0, a.length-1);
}
public void quickSort(Comparable[] a, int lo, int hi)
{
	if (lo >= hi)
		return;
	int j = partition(a, lo, hi);
	quickSort(a, lo, j-1);
	quickSort(a, j+1, hi);
}
public int partition(Comparable[]a, int lo, int hi)
{
	int i = lo, j = hi + 1;		// 左右扫描指针
	Comparable v = a[lo];		// 切分元素
	while (true)
	{
		while (a[++i].compareTo(v) < 0)
			if (i == hi)
				break;
		while (v.compareTo(a[--j]) < 0)
			if (j == lo)
				break;
		if (i >= j)
			break;
		exch(a, i, j);
	}
	exch(a, lo, j);		// 将v=a[j]放入正确的位置
	return j;
}

算法改进:可以先随机打乱数组,再运用快速排序,当相等的元素比较多时,考虑三向切分快速排序

归并排序:将两个有序的数组归并到一个有序的数组,递归发生在处理数组之前,需要借助辅助数组,两个有序数组各自有个从头开始的指针,将较小者依此放入新的大数组中。

自顶向下的归并排序:一般情况,数组并不是能分成左右两个子数组有序,因此采用“分治”的思想,将数组分为两半,再分为两半,。。。,直到每个子数组只有一个元素,开始归并。

Comparable[] aCopy;
public void mergeSort(Comparable[] a)
{
	aCopy = new Comparable[a.length];
	mergeSort(a, 0, a.length-1);
}
public void mergeSort(Comparable[] a, int lo, int hi)
{
	if (hi <= lo)
		return;
	int mid = (lo + hi) / 2;
	mergeSort(a, lo, mid);
	mergeSort(a, mid+1, hi);
	mergeSort(a, lo, mid, hi);
}
public void mergeSort(Comparable[] a, int lo, int mid, int hi)
{
	int i = lo, j = mid + 1;
	for (int k = lo; k <= hi; k++)	// 复制
		aCopy[k] = a[k];
	for (int k = lo; k <= hi; k++)	// 归并
	{
		if (i > mid)
			a[k] = aCopy[j++];
		else if (j > hi)
			a[k] = aCopy[i++];
		else if (aCopy[j].compareTo(aCopy[i]))
			a[k] = aCopy[j++];
		else
			a[k] = aCopy[i++];
 	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值