排序算法(2)--选择排序&堆排序
- 从arr[0]~arr[N]中找出最小的值,放在arr[0],此时arr[0]已经排好序
- 从arr[1]~arr[N]中找出最小的值,放在arr[1],
- ....从arr[i]~arr[N]中找出最小的值,放在arr[i],
- 找到i==N,排序完成
public void sort(int[] arr) { for(int i=0;i<arr.length;i++){ int min = arr[i]; int index = i; for(int j=i+1;j<arr.length;j++){ if(min > arr[j]){ min = arr[j]; index = j; } } int temp = arr[i]; arr[i] = arr[index]; arr[index] = temp; } }
二、堆排序
堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。
(2)、交换数据:将a[0]和a[n]交换,使a[n]是a[0...n]中的最大值;然后将a[0...n-1]重新调整为最大堆。 接着,将a[1]和a[n-1]交换,使a[n-1]是a[1...n-1]中的最大值;然后将a[1...n-2]重新调整为最大值。 依次类推,直到整个数列都是有序的。
(2)、索引为i的左孩子的索引是 (2*i+2);
(3)、索引为i的父结点的索引是 floor((i-1)/2);即取整
在堆排序算法中,首先要将待排序的数组转化成二叉堆。
下面演示将数组{20,30,90,40,70,110,60,10,100,50,80}转换为最大堆{110,100,90,40,80,20,60,10,30,50,70}的步骤。
1.1 i=数组长度/2-1=11/2-1,即i=4
上面是maxheap_down(a, 4, 10)调整过程。maxheap_down(a, 4, 10)的作用是将a[4...10]进行下调;a[4]的左孩子是a[9],右孩子是a[10]。调整时,选择左右孩子中较大的一个(即a[10])和a[4]交换。
1.2 i=3
上面是maxheap_down(a, 3, 10)调整过程。maxheap_down(a, 3, 10)的作用是将a[3...10]进行下调;a[3]的左孩子是a[7],右孩子是a[8]。调整时,选择左右孩子中较大的一个(即a[8])和a[4]交换。
1.3 i=2
上面是maxheap_down(a, 2, 10)调整过程。maxheap_down(a, 2, 10)的作用是将a[2...10]进行下调;a[2]的左孩子是a[5],右孩子是a[6]。调整时,选择左右孩子中较大的一个(即a[5])和a[2]交换。
1.4 i=1
上面是maxheap_down(a, 1, 10)调整过程。maxheap_down(a, 1, 10)的作用是将a[1...10]进行下调;a[1]的左孩子是a[3],右孩子是a[4]。调整时,选择左右孩子中较大的一个(即a[3])和a[1]交换。
交换之后,a[3]为30,它比它的右孩子a[8]要大,接着,再将它们交换。
1.5 i=0
上面是maxheap_down(a, 0, 10)调整过程。maxheap_down(a, 0, 10)的作用是将a[0...10]进行下调;a[0]的左孩子是a[1],右孩子是a[2]。调整时,选择左右孩子中较大的一个(即a[2])和a[0]交换。
交换之后,a[2]为20,它比它的左右孩子要大,选择较大的孩子(即左孩子)和a[2]交换。
调整完毕,就得到了最大堆。此时,数组{20,30,90,40,70,110,60,10,100,50,80}也就变成了{110,100,90,40,80,20,60,10,30,50,70}。
(2)、交换数据
在将数组转换成最大堆之后,接着要进行交换数据,从而使数组成为一个真正的有序数组。
交换数据部分相对比较简单,下面仅仅给出将最大值放在数组末尾的示意图。
上面是当n=10时,交换数据的示意图。
当n=10时,首先交换a[0]和a[10],使得a[10]是a[0...10]之间的最大值;然后,调整a[0...9]使它称为最大堆。交换之后:a[10]是有序的。
当n=9时, 首先交换a[0]和a[9],使得a[9]是a[0...9]之间的最大值;然后,调整a[0...8]使它称为最大堆。交换之后:a[9...10]是有序的。
...
依此类推,直到a[0...10]是有序的。
private void maxHeapDown(int arr[],int start,int end){ int parentIndex = start;//1.1 节点 int left = 2*parentIndex+1;//1.2 先找到左节点 while(left<=end){ int maxIndex =left;//2.左右节点中 数据大的节点 if((left+1) <= end && arr[left]<arr[left+1]){ maxIndex = left+1; } int parentValue = arr[parentIndex]; if(parentValue > arr[maxIndex]){ break; } //3、交换节点 arr[parentIndex] = arr[maxIndex]; arr[maxIndex] = parentValue; //4.继续处理 parentIndex = maxIndex; left = 2*parentIndex+1; } } public void heapSort(int arr[]){ // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。 for(int i=arr.length/2-1; i>=0; i--){ maxHeapDown(arr, i, arr.length-1); } for(int i=arr.length-1;i>0;i--){ int temp = arr[i]; arr[i] = arr[0]; arr[0] = temp;//arr[0]和arr[i]交换。交换后arr[i]是arr[0]~arr[i-1]最大的 maxHeapDown(arr, 0, i-1);//对剩余的堆栈进行调整 } }