选择排序与堆排序

选择排序 
依次选择数组中的最小值(从小到大),并按顺序排放。
从第一个数开始,依次遍历数组中的数据,找出最小值,并与第一个数交换位置;
从第二个数开始,依次遍历(剩余)数组中的数据,找出最小值,并与第二个数交换位置;
... ...

堆排序
堆的概念:在一颗完全二叉树中,子结点的值总是小于父结点的值(大根堆),或者子结点的值总是大于父结点的值(小根堆)。

我想,堆排序之所以也属于选择排序,是因为它总是从堆中选择最大值(降序是最小值)交换于数据尾部。

排序过程:

1.我们将数组“理解(视)为”逻辑中的二叉树;
   例如:int array[10] = {9,8,7,1,2,3,6,5,4,0};
   层序存放:


2.将二叉树调整为二叉堆(如果是升序排列,使用大根堆)

   从最后一个有孩子的结点的位置(node=(length -1)/2)开始,调整“父”与“子”结点的位置(使子结点的值总是小于父结点的值,左右子结点大小无所谓),直到调整至根结点。   
   调整后的输出:  
 
   (这里只是将5和1做了交换)
  
3. 将根结点与尾结点进行交换(此时的尾结点不一定是最小值)
    {
      temp = array[0];
      array[0] = array[heapSize];
      array[heapSize] = temp; 
      heapSize--;
    }
    因为此时根结点为最大值,即:将最大值挪动到最后位置,此后不再“关注”。
    输出:  
 
    (这里将9和0做了交换,9不再参与之后的比较、调整)   

4.
(递归)重复步骤2  
    调整后的输出:  

 


5. 重复步骤3      
    输出:  
 
   (这里将8和0做了交换,8不再参与之后的比较、调整)      
   
6. (递归)重复步骤2和3   
    最终,得到结果:
 
   对应的数组array[10] = {0,1,2,3,4,5,6,7,8,9};


在理解“堆排序”之前,我有2个疑惑:   
1. 数组的存储为什么不调整为BST树?   
    数组如果表示为BST的存储,BST的树高不确定,将会借助更大的存储空间;(如果想降低树的高度,必须旋转)


2. 如果数据本来就是按照升序排列(小顶堆),然后又来构建大顶堆,岂不是多此一举?  

    这就是为什么堆排序的时间复杂度(最小、平均、最大)总是O(NlogN)。

#include<stdio.h>

//打印
void display(int array[], int n)
{
    for (int i = 0; i < n; i++) 
	{
        printf("%d ", array[i]);
    }
    printf("\n");
}

//选择排序
void selectionSort(int array[], int n)
{
    int i, j, index, value;
    //i,可以理解为数组下标,从i开始遍历,查找数组中的最小值;
	//当找到最小值,放置到下标i的位置,然后从i+1继续查找最小值。
    for (i = 0; i < n - 1; i ++) 
	{
	    //index,最小值下标
        index = i;
		//最小值
        value = array[i];
		//循环遍历找到最小值
        for (j = i + 1; j < n; j ++)
		{
            if (value > array[j]) 
			{			    
                index = j;
                value = array[j];
            }
			//display(array, n);
		}
		//寻得本轮最小值后,(通过交换)放置到适当的位置。
        array[index] = array[i];
		//value即当前最小值,把它放置到位置i
        array[i] = value;	
        display(array, n);
    }
}

//堆调整
void heapAdjust(int array[], int node, int heapSize)
{
	display(array, heapSize+1);

	int leftChild, rightChild, largest, temp;
	//左孩子结点
	leftChild = 2*node+1;
	//右孩子结点
	rightChild = 2*node + 2;
	//比较当前结点、左孩子、右孩子中的最大值
	if(leftChild <= heapSize && array[leftChild] > array[node])
	{
		largest = leftChild;
	}
	else
	{
		largest = node;
	}
	if( rightChild <= heapSize && array[rightChild] > array[largest])
	{
		largest = rightChild;
	}
	//如果最大值不是“结点值”,“结点值”与其孩子中的“大值”交换。
	if(largest != node)
	{
		temp = array[node];
		array[node] = array[largest];
		array[largest] = temp;
		heapAdjust(array, largest, heapSize);
	}
}

//构建大顶堆,
//如果本来数据就是按照升序排列,然后又来构建大顶堆,岂不是多此一举?
void buildHeap(int array[], int length)
{
	int node, heapSize;
	//heapSize实际与数据下标对应,所以要减1
	heapSize = length - 1;
	//最后一个有孩子的节点的位置 node =  (length -1) / 2  
	for( node=(length-1)/2; node >= 0; node--)
	{
		heapAdjust(array, node, heapSize);
	} 
}

//堆排序
void heapSort(int array[], int length)
{
	buildHeap(array, length);
	int heapSize, i, temp;
	heapSize = length - 1;
	//heapsize,堆的最末一位
	for( i=heapSize; i >= 0; i--)
	{
		//array[0],堆顶,即堆内最大数据;与array[heapSize]交换,array[heapSize]是堆末数据(不一定为最小数据)
		temp = array[0];
		array[0] = array[heapSize];
		array[heapSize] = temp;
		//堆内最大数据被放置到当前堆末位后,--降堆,
		heapSize--;
		heapAdjust(array, 0, heapSize);
	}
	display(array, length);
}

int main()
{
    printf("==============Test Selection Sort ==============\n");	
    int array[10] = {9,8,7,1,2,3,6,5,4,0};
    //int array[10] = {9,8,7,6,5,4,3,2,1,0};
    //int array[10] = {0,1,2,3,4,5,6,7,8,9};
    selectionSort(array, 10);
	
    printf("==============Test Heap Sort ==============\n");	
	int array10[10] = {9,8,7,1,2,3,6,5,4,0};
	//int array11[10] = {9,8,7,6,5,4,3,2,1,0};
	//int array12[10] = {0,1,2,3,4,5,6,7,8,9};
	heapSort(array10, 10);
  
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值