博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
选择排序(C++/Java实现)
阅读量:6679 次
发布时间:2019-06-25

本文共 9274 字,大约阅读时间需要 30 分钟。

常用的选择排序算法有两种:直接选择排序和堆排序。 

一、直接选择排序

基本思路:

第一趟比较:程序将记录定位在第一个数据上,拿第一个数据依次和后面的数据进行比较,如果第一个数据大于后面的某个数据,交换它们,....依次进行下去。这趟比较将选出最小的数据并将其排在第一位。

第二趟比较:程序将记录定位在第二个数据上,拿第二个数据依次和后面的数据进行比较,如果第二个数据大于后面的某个数据,交换它们,....依次进行下去。这趟比较将选出第二小的数据并将其排在第二位。

......

依此规则进行比较n-1趟,这组数据中第2大的数据被选出之后,被排在倒数第1位,剩下的就是最大的数了。

Java实现代码:

//定义一个数据包装类  public class DataWrap implements Comparable
{ int data; String flag; public DataWrap(int data, String flag) { this.data = data; this.flag = flag; } public String toString() { return data + flag; } //根据data实例变量来决定两个DataWrap的大小 public int compareTo(DataWrap dw) { return this.data > dw.data ? 1 : (this.data == dw.data ? 0 : -1); } }

直接选择排序:

//选择排序public class SelectSort  {      public static void selectSort(DataWrap[] data)       {          System.out.println("开始排序");          int arrayLength = data.length;          //依次进行n-1趟比较, 第i趟比较将第i大的值选出放在i位置上。          for (int i = 0; i < arrayLength - 1 ; i++ )          {              //第i个数据只需和它后面的数据比较              for (int j = i + 1 ; j < arrayLength ; j++ )              {                                 //如果第i位置的数据 > j位置的数据, 交换它们                  if (data[i].compareTo(data[j]) > 0)                  {                      DataWrap tmp = data[i];                      data[i] = data[j];                      data[j] = tmp;                  }              }              System.out.println(java.util.Arrays.toString(data));          }      }      public static void main(String[] args)      {          DataWrap[] data = {              new DataWrap(21 , ""),              new DataWrap(30 , ""),              new DataWrap(49 , ""),              new DataWrap(30 , "*"),              new DataWrap(16 , ""),              new DataWrap(9 , "")          };          System.out.println("排序之前:\n"              + java.util.Arrays.toString(data));          selectSort(data);          System.out.println("排序之后:\n"               + java.util.Arrays.toString(data));      }  }

下面是排序过程:

排序之前:

[21, 30, 49, 30*, 16, 9]
开始排序
[9, 30, 49, 30*, 21, 16]
[9, 16, 49, 30*, 30, 21]
[9, 16, 21, 49, 30, 30*]
[9, 16, 21, 30, 49, 30*]
[9, 16, 21, 30, 30*, 49]
排序之后:
[9, 16, 21, 30, 30*, 49]

对上面的算法改进,每次找到最小的数据的索引,减少交换的次数,提高算法效率: 

public class SelectSort2  {      public static void selectSort(DataWrap[] data)       {          System.out.println("开始排序");          int arrayLength = data.length;          //依次进行n-1趟比较, 第i趟比较将第i大的值选出放在i位置上。          for (int i = 0; i < arrayLength - 1 ; i++ )          {              //minIndex永远保留本趟比较中最小值的索引              int minIndex = i ;              //第i个数据只需和它后面的数据比较              for (int j = i + 1 ; j < arrayLength ; j++ )              {                  //如果第minIndex位置的数据 > j位置的数据                  if (data[minIndex].compareTo(data[j]) > 0)                  {                      //将j的值赋给minIndex                      minIndex = j;                  }              }              //每趟比较最多交换一次              if (minIndex != i)              {                  DataWrap tmp = data[i];                  data[i] = data[minIndex];                  data[minIndex] = tmp;              }              System.out.println(java.util.Arrays.toString(data));          }      }      public static void main(String[] args)      {          DataWrap[] data = {              new DataWrap(21 , ""),              new DataWrap(30 , ""),              new DataWrap(49 , ""),              new DataWrap(30 , "*"),              new DataWrap(16 , ""),              new DataWrap(9 , "")          };          System.out.println("排序之前:\n"              + java.util.Arrays.toString(data));          selectSort(data);          System.out.println("排序之后:\n"               + java.util.Arrays.toString(data));      }  }

下面是排序过程:

排序之前:

[21, 30, 49, 30*, 16, 9]
开始排序
[9, 30, 49, 30*, 16, 21]
[9, 16, 49, 30*, 30, 21]
[9, 16, 21, 30*, 30, 49] 不交换
[9, 16, 21, 30*, 30, 49] 不交换
[9, 16, 21, 30*, 30, 49]
排序之后:
[9, 16, 21, 30*, 30, 49]

可以看出:直接选择排序的第n趟比较至多交换一次,永远总是拿n-1位的数据和中间某个数据(本趟比较中最小的数据)进行交换。如果本趟比较时第n-1位(本趟比较的第一位)数据已经是最小,则无需进行交换。

 C++代码实现:

 

#include
using namespace std;//直接选择排序void select_sort(int a[],int len){ int i,j,x,l; for(i=0;i

 

二、堆排序

首先,关于堆的概念这里就不说了,详情请看《算法导论》

堆排序的关键在于建堆,下面简单介绍一下建堆的过程:

第1趟将索引0至n-1处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的最后一个节点交换,就使的这组数据中最大(最小)值排在了最后。

第2趟将索引0至n-2处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的倒数第二个节点交换,就使的这组数据中最大(最小)值排在了倒数第二位。

......

第k趟将索引0至n-k处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的倒数第k个节点交换,就使的这组数据中最大(最小)值排在了倒数第k位。

所以我们只是在重复做两件事:

1:建堆

2:拿堆的根节点和最后一个节点交换

下面通过一组数据说明:

9,79,46,30,58,49

1:先将其转换为完全二叉树,如图

 

2:完全二叉树的最后一个非叶子节点,也就是最后一个节点的父节点。最后一个节点的索引为数组长度len-1,那么最后一个非叶子节点的索引应该是为(len-1)/2.也就是从索引为2的节点开始,如果其子节点的值大于其本身的值。则把他和较大子节点进行交换,即将索引2处节点和索引5处元素交换。交换后的结果如图:

建堆从最后一个非叶子节点开始即可

3:向前处理前一个节点,也就是处理索引为1的节点,此时79>30,79>58,因此无需交换。

4:向前处理前一个节点,也就是处理索引为0的节点,此时9<79,9<49,因此无需交换。应该拿索引为0的节点与索引为1的节点交换,因为79>49.如图

 

 

5:如果某个节点和它的某个子节点交换后,该子节点又有子节点,系统还需要再次对该子节点进行判断。如上图因为1处,3处,4处中,1处的值大于3,4出的值,所以还要交换。

Java代码实现:

//堆排序public class HeapSort  {      public static void heapSort(DataWrap[] data)       {          System.out.println("开始排序");          int arrayLength = data.length;          //循环建堆          for (int i = 0; i < arrayLength - 1 ; i++ )          {              //建堆              builMaxdHeap(data , arrayLength - 1 - i);              //交换堆顶和最后一个元素              swap(data , 0 , arrayLength - 1 - i);              System.out.println(java.util.Arrays.toString(data));          }      }      //对data数组从0到lastIndex建大顶堆      private static void builMaxdHeap(DataWrap[] data , int lastIndex)      {          //从lastIndex处节点(最后一个节点)的父节点开始          for (int i = (lastIndex - 1) / 2 ; i >= 0  ; i--)          {              //k保存当前正在判断的节点              int k = i;              //如果当前k节点的子节点存在              while (k * 2 + 1 <= lastIndex)              {                  //k节点的左子节点的索引                  int biggerIndex = 2 * k  + 1;                   //如果biggerIndex小于lastIndex,即biggerIndex + 1                  //代表的k节点的右子节点存在                  if (biggerIndex < lastIndex)                  {                       //如果右子节点的值较大                      if(data[biggerIndex].compareTo(data[biggerIndex + 1]) < 0)                      {                          //biggerIndex总是记录较大子节点的索引                          biggerIndex++;                       }                  }                  //如果k节点的值小于其较大子节点的值                  if(data[k].compareTo(data[biggerIndex]) < 0)                  {                      //交换它们                      swap(data , k , biggerIndex);                      //将biggerIndex赋给k,开始while循环的下一次循环,                      //重新保证k节点的值大于其左、右子节点的值。                      k = biggerIndex;                  }                  else                  {                      break;                  }              }          }      }      //交换data数组中i、j两个索引处的元素      private static void swap(DataWrap[] data , int i , int j)      {          DataWrap tmp = data[i];          data[i] = data[j];          data[j] = tmp;      }      public static void main(String[] args)      {          DataWrap[] data = {              new DataWrap(21 , ""),              new DataWrap(30 , ""),              new DataWrap(49 , ""),              new DataWrap(30 , "*"),              new DataWrap(21 , "*"),              new DataWrap(16 , ""),              new DataWrap(9 , "")          };          System.out.println("排序之前:\n"              + java.util.Arrays.toString(data));          heapSort(data);          System.out.println("排序之后:\n"               + java.util.Arrays.toString(data));      }  }

实现过程:

排序之前:

[21, 30, 49, 30*, 21*, 16, 9]
开始排序
[9, 30, 21, 30*, 21*, 16, 49]
[16, 30*, 21, 9, 21*, 30, 49]
[16, 21*, 21, 9, 30*, 30, 49]
[9, 16, 21, 21*, 30*, 30, 49]
[9, 16, 21, 21*, 30*, 30, 49]
[9, 16, 21, 21*, 30*, 30, 49]
排序之后:
[9, 16, 21, 21*, 30*, 30, 49]

 

C++实现:

 

#include
using namespace std;int heapSize = 0;void swap(int array[] , int i , int j){ int temp; temp = array[i]; array[i] = array[j]; array[j] = temp;}//array[index]与其左右子树进行递归对比,用最大值替换array[index],index表示堆顶索引void MaxHeapify(int array[] , int index ){ int left = 2*index;//左子节点索引 int right = 2*index+1;//右子节点索引 int largest;//最大数 //用largest存储堆顶与其左子节点的较大者 if(left<=heapSize && array[left]>array[index]) largest = left; else largest = index; //用largest存储堆顶与其右子节点的较大者 if(right<=heapSize && array[right]>array[largest]) largest = right; //此时largest为堆顶,左子节点,右子节点最大者 if(largest != index) { //如果堆顶不是最大者,则交换,并递归调整堆 swap(array , index , largest); MaxHeapify(array , largest); }} //初始化堆,将数组中的每一个元素放到合适的位置。此时堆顶的元素为数组的最大值void BuildMaxHeap(int array[],int length ){ heapSize = length; for(int i=length-1 ; i>=0 ; i--) { MaxHeapify(array , i ); }} //排序void HeapSort(int array[] , int length){ //初始化堆 BuildMaxHeap(array,length); for(int i=length ; i>=1 ; i--) { swap(array , 0 , i); //堆顶元素array[0](即数组的最大值)被置换到数组的尾部array[i] heapSize--;//从堆中移除该元素 MaxHeapify(array , 0);//重建堆 }}int main(){ int a[8] = {68,20,39,88,97,46,59,11}; int i; HeapSort(a,8); for(i=0 ; i<8 ; i++) { cout << a[i] << " "; } cout <

 

这是经过改正的,终于解决了.....

 

转载地址:http://eqnao.baihongyu.com/

你可能感兴趣的文章
GitOSC和GitHub上传项目
查看>>
全局静态变量析构和线程结束先后顺序问题
查看>>
[PYTHON] 核心编程笔记(12.Python模块)
查看>>
windows下MD5-SHA1校验
查看>>
Linux学习记录-2015-08-20--常用命令1
查看>>
Android工程引用另外一个工程的正确/错误方法
查看>>
Testlink使用介绍
查看>>
【动态规划】0-1背包问题原理和实现
查看>>
c3p0详细配置
查看>>
jsfl导出库里面的PNG图片
查看>>
PostgreSQL的MVCC vs InnoDB的MVCC
查看>>
COMP9321/19T1/resources/22490
查看>>
使用JSON实现分页
查看>>
如何优雅地使用Markdown (Sublime 3 + MarkdownEditing+OmniMarkupPreviewer)
查看>>
HTML+5+从入门到精通
查看>>
安全退出调用多个Activity的Application
查看>>
pdf怎么编辑连续页码
查看>>
非openresty方式安装Nginx + Lua + Redis 环境
查看>>
记2012-2013年一路的Windows Phone历程
查看>>
本博客搬家辣
查看>>