快速排序,归并排序,堆排序模板java代码
目录
1、快速排序
快速排序原理:
1.首先设定一个分界值,通过该分界值将数组分成左右两部分;
2.将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于
或等于分界值,而右边部分中各元素都大于或等于分界值;
3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两
部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当
左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了。
切分原理:
把一个数组切分成两个子数组的基本思想:
1.找一个基准值,用两个指针分别指向数组的头部和尾部;
2.先从尾部向头部开始搜索一个比基准值小的元素,搜索到即停止,并记录指针的位置;
3.再从头部向尾部开始搜索一个比基准值大的元素,搜索到即停止,并记录指针的位置;
4.交换当前左边指针位置和右边指针位置的元素;
5.重复2,3,4步骤,直到左边指针的值大于右边指针的值停止。
源代码:
//排序代码
public class Quick
{
public static void sort(Comparable[] a)
{
int lo = 0;
int hi = a.length - 1;
sort(a, lo,hi);
}
private static void sort(Comparable[] a, int lo, int hi)
{
if (hi<=lo)
{
return;
}
//对a数组中,从lo到hi的元素进行切分
int partition = partition(a, lo, hi);
//对左边分组中的元素进行排序
//对右边分组中的元素进行排序
sort(a,lo,partition-1);
sort(a,partition+1,hi);
}
public static int partition(Comparable[] a, int lo, int hi)
{
Comparable key=a[lo];//把最左边的元素当做基准值
int left=lo;//定义一个左侧指针,初始指向最左边的元素
int right=hi+1;//定义一个右侧指针,初始指向左右侧的元素下一个位置
//进行切分
while(true)
{
//先从右往左扫描,找到一个比基准值小的元素
while(less(key,a[--right]))
{//循环停止,证明找到了一个比基准值小的元素
if (right==lo)
{
break;//已经扫描到最左边了,无需继续扫描
}
}
//再从左往右扫描,找一个比基准值大的元素
while(less(a[++left],key))
{//循环停止,证明找到了一个比基准值大的元素
if (left==hi)
{
break;//已经扫描到了最右边了,无需继续扫描
}
}
if (left>=right)
{
//扫描完了所有元素,结束循环
break;
}
else
{
//交换left和right索引处的元素
exch(a,left,right);
}
}
//交换最后rigth索引处和基准值所在的索引处的值
exch(a,lo,right);
return right;//right就是切分的界限
}
/*
数组元素i和j交换位置
*/
private static void exch(Comparable[] a, int i, int j)
{
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
/*
比较v元素是否小于w元素
*/
private static boolean less(Comparable v, Comparable w)
{
return v.compareTo(w) < 0;
}
}
//测试代码
public class Test
{
public static void main(String[] args) throws Exception
{
Integer[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 8};
Quick.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
2、归并排序
归并排序原理:
1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是 1为止。
2.将相邻的两个子组进行合并成一个有序的大组;
3.不断的重复步骤2,直到最终只有一个组为止。
归并原理
源代码:
//排序代码
public class Merge
{
private static Comparable[] assist;//归并所需要的辅助数组
/*
对数组a中的元素进行排序
*/
public static void sort(Comparable[] a)
{
assist = new Comparable[a.length];
int lo = 0;
int hi = a.length-1;
sort(a, lo, hi);
}
/*
对数组a中从lo到hi的元素进行排序
*/
private static void sort(Comparable[] a, int lo, int hi)
{
if (hi <= lo)
{
return;
}
int mid = lo + (hi - lo) / 2;
//对lo到mid之间的元素进行排序;
sort(a, lo, mid);
//对mid+1到hi之间的元素进行排序;
sort(a, mid+1, hi);
//对lo到mid这组数据和mid到hi这组数据进行归并
merge(a, lo, mid, hi);
}
/*
对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
*/
private static void merge(Comparable[] a, int lo, int mid, int hi)
{
//lo到mid这组数据和mid+1到hi这组数据归并到辅助数组assist对应的索引处
int i = lo;//定义一个指针,指向assist数组中开始填充数据的索引
int p1 = lo;//定义一个指针,指向第一组数据的第一个元素
int p2 = mid + 1;//定义一个指针,指向第二组数据的第一个元素
//比较左边小组和右边小组中的元素大小,哪个小,就把哪个数据填充到assist数组中
while (p1 <= mid && p2 <= hi)
{
if (less(a[p1], a[p2]))
{
assist[i++] = a[p1++];
}
else
{
assist[i++] = a[p2++];
}
}
//上面的循环结束后,如果退出循环的条件是p1<=mid,则证明左边小组中的数据已经归并完毕,如 果退出循环的条件是p2<=hi,则证明右边小组的数据已经填充完毕;
//所以需要把未填充完毕的数据继续填充到assist中,//下面两个循环,只会执行其中的一个
while(p1<=mid)
{
assist[i++]=a[p1++];
}
while(p2<=hi)
{
assist[i++]=a[p2++];
}
//到现在为止,assist数组中,从lo到hi的元素是有序的,再把数据拷贝到a数组中对应的索引处
for (int index=lo;index<=hi;index++)
{
a[index]=assist[index];
}
}
/*
比较v元素是否小于w元素
*/
private static boolean less(Comparable v, Comparable w)
{
return v.compareTo(w) < 0;
}
/*
数组元素i和j交换位置
*/
private static void exch(Comparable[] a, int i, int j)
{
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//测试代码
public class Test
{
public static void main(String[] args) throws Exception
{
Integer[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
Merge.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
3、堆排序
堆排序原理
1.构造堆;
2.得到堆顶元素,这个值就是最大值;
3.交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;
4.对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;
5.重复2~4这个步骤,直到堆中剩一个元素为止。
堆的构造,最直观的想法就是另外再创建一个和新数组数组,然后从左往右遍历原数组,每得到一个元素后,添加 到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。 上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。创建一个新数组,把原数组 0~length-1的数据拷贝到新数组的1~length处,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后 对扫描到的每一个元素做下沉调整即可。
堆排序过程
对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。
1.将堆顶元素和堆中最后一个元素交换位置;
2.通过对堆顶元素下沉调整堆,把最大的元素放到堆顶(此时最后一个元素不参与堆的调整,因为最大的数据已经到 了数组的最右边)
3.重复1~2步骤,直到堆中剩最后一个元素。
源代码
//堆排序代码
public class HeapSort
{
//对source数组中的数据从小到大排序
public static void sort(Comparable[] source)
{
//1.创建一个比原数组大1的数组
Comparable[] heap = new Comparable[source.length + 1];
//2.构造堆
createHeap(source,heap);
//3.堆排序
//3.1定义一个变量,记录heap中未排序的所有元素中最大的索引
int N = heap.length-1;
while(N!=1)
{
//3.2交换heap中索引1处的元素和N处的元素
exch(heap,1,N);
N--;
//3.3对索引1处的元素在0~N范围内做下沉操作
sink(heap,1,N);
}
//4.heap中的数据已经有序,拷贝到source中
System.arraycopy(heap,1,source,0,source.length);
}
//根据原数组source,构造出堆heap
private static void createHeap(Comparable[] source, Comparable[] heap)
{
//1.把source中的数据拷贝到heap中,从heap的1索引处开始填充
System.arraycopy(source,0,heap,1,source.length);
//2.从heap索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作
for (int i = (heap.length-1)/2; i>0 ; i--)
{
sink(heap,i,heap.length-1);
}
}
//判断heap堆中索引i处的元素是否小于索引j处的元素
private static boolean less(Comparable[] heap, int i, int j)
{
return heap[i].compareTo(heap[j])<0;
}
//交换heap堆中i索引和j索引处的值
private static void exch(Comparable[] heap, int i, int j)
{
Comparable tmp = heap[i];
heap[i] = heap[j];
heap[j] = tmp;
}
//在heap堆中,对target处的元素做下沉,范围是0~range
private static void sink(Comparable[] heap, int target, int range)
{
//没有子结点了
while (2*target<=range)
{
//1.找出target结点的两个子结点中的较大值
int max=2*target;
if (2*target+1<=range)
{
//存在右子结点
if (less(heap,2*target,2*target+1))
{
max=2*target+1;
}
}
//2.如果当前结点的值小于子结点中的较大值,则交换
if(less(heap,target,max))
{
exch(heap,target,max);
}
//3.更新target的值
target=max;
}
}
}
//测试代码
public class Test
{
public static void main(String[] args) throws Exception
{
String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
HeapSort.sort(arr);
System.out.println(Arrays.toString(arr));
}
}