选择排序的基本宗旨就是每次选出剩余元素中最大的或者最小放在最终排序的对应位置。
1.直接选择排序
基本思想:
在a[1]-a[n-1]中选择最小的元素和a[0]交换;
在a[2]-a[n-1]中选择最小的元素和a[1]交换;
……
在a[i]-a[n-1]中选择最下的元素和a[i-1]交换;
以此类推。。。。。。
算法步骤:
循环比较:
第一轮:将a[0]和a[1]-a[n-1]中的每个元素依次比较,若出现a[0]>a[j],则将两者进行交换;由此可以将数组中最小的元素放到a[0];
第二轮:将a[1]和a[2]-a[n-1]中的每个元素依次比较。同样若出现a[1]>a[j],则将两者交换,由此将倒数第二小的元素放到a[1];
依次类推。。。
代码实现:
public class SelectedSort {
//测试
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = {2,5,1,7,4,3,6};
sort(a);
}
//排序
public static void sort(int[] a){
//双重循环,依次比较大小
for(int i = 0;i<a.length-1;i++){
for(int j = i+1;j<a.length;j++){
if(a[j]<a[i]){
int tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
}
for(int i = 0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
2.直接选择排序的改进
在直接选择排序中,如在第一轮比较中,一旦找到比a[0]小的元素便进行交换,这样导致最多需要n-1次比较和交换才能找到最小的元素,但是我们每轮比较的目的是选出最小的元素放到a[0]上,所以可以改进上诉的算法,在找到最小元素后再跟a[0]进行交换,这样只需要交换一次即可。
算法实现:设置一个标记为,每次标记较小的元素所在的位置,直到找到最小的元素位置,然后直接进行交换即可。
代码实现:
public class SelectedSort {
public static void main(String[] args) {
int[] a = {2,5,1,7,4,3,6};
sort(a);
}
public static void sort(int[] a){
int minI = 0;
for(int i = 0;i<a.length-1;i++){
minI = i;
for(int j = i+1;j<a.length;j++){
if(a[j]<a[minI]){
minI = j;
}
}
if(minI!=i){
int tmp = a[minI];
a[minI] = a[i];
a[i] = tmp;
}
}
for(int i = 0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
3.堆排序
这篇博文介绍了堆排序,生动简单清晰,所以这里多数是参考来写的,侵权删。https://www.cnblogs.com/chengxiao/p/6129630.html
(1)堆
堆是一种特殊的几乎完全二叉树。
堆的性质:叶子结点的键值或索引总是小于(或者大于)它的父节点(大顶堆和小顶堆)。
对堆的访问:
根节点的位置为0;
父节点i的左子节点在位置 (2*i+1);
父节点i的右子节点在位置 (2*i+2);
子节点i的父节点在位置 (i-1)/2;
最后一个非叶子节点的下标是n/2-1 ,因为其为最后一个节点(n-1)的父节点。
堆结构映射为数组即为如下所示:
(2)堆排序(升序采用大顶堆,降序采用小顶堆)
基本思想:将待排序的数组构造成一个大顶堆,那么此时根节点的元素即为最大值,将其与最后一个叶子节点进行交换,即将最大元素放置在了末尾;然后将剩余的n-1个元素重新构造成一个大顶堆,依次类推,最终完成对数组的排序。
实现步骤:
A. 根据给定无序数组构造一个大顶堆。
给定的无序数据如下(设长度为n,此出n=5):
首先从最后一个非叶子节点开始调整,因为叶子节点需要跟着其父节点进行调整。第一个非叶子节点为n/2-1,即数值为6的节点。
对于堆结构来说,因为堆是一个完全二叉树,所以肯定存在左子节点,所以首先判断是否存在右子节点,若存在,则将两个子节点进行比较,将数值大的子节点再与父节点比较,进而当子节点>父节点的情况下,父节点与子节点进行交换。
如图,6和9进行交换。
找到第二个非叶子节点4,同理将4和9交换。
明显可以看出,但是这步交换导致[4,5,6]不满足堆结构,所以需要继续调整。
至此,成功构成一个大顶堆。
B.将根节点和最后一个叶子节点进行交换,并且需要对n-1个元素继续调整成堆(从根节点开始调整,因为除了根节点外其他均已满足堆结构),以此类推,不断进行交换,重建。。。。。。
将4和9进行交换
重新构建大顶堆
将8和5交换
以此接着调整和交换,最终得到如下有序序列
堆排序基本思路总结:
a. 首先从最后一个非叶子节点,从右至左,从下至上,将无序序列构建成一个大顶堆;
b.将根节点与最后一个叶子节点进行交换,得到最大元素;
c.因为根节点发生了变化,其他父节点均满足堆结构,所以从根节点开始调整,将剩余元素继续构造成大顶堆,并交换根节点和最后一个叶子节点,直到完成排序。
代码实现如下:
public class HeapSort1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = {2,3,1,4,6,0};
sort(a);
for(int i = 0;i<a.length;i++)
System.out.println(a[i]);
}
public static void sort(int[] a){
int n = a.length;
int t = 0;
//初始化大根堆,从最后一个非叶子节点开始调整
for(int i=(a.length/2-1);i>-1;i--){
adjustHeap(a,i,n);
}
//交换元素并继续调整,从根节点开始调整
for(int i=n-1;i>-1;i--){
int tmp = a[i];
a[i] = a[0];
a[0] = tmp;
adjustHeap(a,0,i);
}
}
//对某一个父节点进行调整
public static void adjustHeap(int[] a, int parent, int length){
int temp = a[parent];
int child = parent*2+1;//从左子节点开始
while(child < length-1){
//判断是否存在右子叶子节点,并将大的赋值给child
if(child+1<length && a[child]<a[child+1]){
child++;
}
//判断父节点是否比子节点大,若大于则说明当前父节点无需接着进行调整
if(temp > a[child])
break;
//否则交换父节点和子节点
a[parent] = a[child];
//因上面的调整影响到下面节点,所以接着进行调整
parent = child;
child = parent *2+1;
}
a[parent] = temp;
}
}
总结:
选择排序的基本思想就是每次都选择出当前最大或者最小的元素直接放到相应的位置上。