堆排序算法-OC实现

  • 简介

堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,两者对左右孩子的大小关系不做任何要求,其实很好理解。有了上面的定义,我们可以得知,处于最大堆的根节点的元素一定是这个堆中的最大值。

  • 算法原理

1、将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区
2、将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn)
3、由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成

  • C语言实现
//最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
void maxHeapify(int numbers[], int start, int end) {
    //建立父节点指标和子节点指标
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子节点指标在范围内才做比较
        if (son + 1 <= end && numbers[son] < numbers[son + 1]) { //先比较两个子节点大小,选择最大的
            son++;
        }
        if (numbers[dad] > numbers[son]) {//如果父节点大于子节点代表调整完毕,直接跳出函数
            return;
        }else { //否则交换父子内容再继续子节点和孙节点比较
            int temp = numbers[son];
            numbers[son] = numbers[dad];
            numbers[dad] = temp;
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

/**堆排序(HeapSort):
 1、首先从最后一个父节点做最大堆调整,找出最大值,此时最大值位于根节点
 2、然后将最大值和已排好元素(依次找出的最大值排出的序列,如:6 3 9 23 12 8 [15 16 17 18])前一位元素交换位置,再将除已排好元素外的其他元素(6 3 9 23 12 8)做最大堆调整,找出最大值,此时最大值位于根节点
 3、重复步骤2,直至结束
 */
void heapSort(int numbers[], int length) {
    //初始化,i从最後一个父节点开始做最大堆调整,调整结束后根节点得到最大值
    for (int i = length / 2 - 1; i >= 0; i--) {
        maxHeapify(numbers, i, length - 1);
    }
    //先将第一个元素和已排好元素前一位做交换,再重新调整,直到排序完毕
    for (int i = length - 1; i > 0; i--) {
        int temp = numbers[0];
        numbers[0] = numbers[i];
        numbers[i] = temp;
        maxHeapify(numbers, 0, i - 1);
    }
}

//调用
    int number[5] = {95, 45, 15, 78, 84};
    heapSort(number, 5);
    for (i = 0; i < 5; i++) {
        printf("%d\n", number[i]);
    }
  • OC实现
//最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
- (void)maxHeapifyWithNumbers:(NSMutableArray *)numbers start:(int)start end:(int)end {
    //建立父节点指标和子节点指标
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子节点指标在范围内才做比较
        if (son + 1 <= end && [numbers[son] intValue] < [numbers[son + 1] intValue]) { //先比较两个子节点大小,选择最大的
            son++;
        }
        if ([numbers[dad] intValue] > [numbers[son] intValue]) {//如果父节点大于子节点代表调整完毕,直接跳出函数
            return;
        }else { //否则交换父子内容再继续子节点和孙节点比较
            [numbers exchangeObjectAtIndex:son withObjectAtIndex:dad];
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

/**堆排序(HeapSort):
 1、首先从最后一个父节点做最大堆调整,找出最大值,此时最大值位于根节点
 2、然后将最大值和已排好元素(依次找出的最大值排出的序列,如:6 3 9 23 12 8 [15 16 17 18])前一位元素交换位置,再将除已排好元素外的其他元素(6 3 9 23 12 8)做最大堆调整,找出最大值,此时最大值位于根节点
 3、重复步骤2,直至结束
 */
- (void)heapSortWithNumbers:(NSMutableArray *)numbers {
    //初始化,i从最後一个父节点开始做最大堆调整,调整结束后根节点得到最大值
    for (int i = (int)numbers.count / 2 - 1; i >= 0; i--) {
        [self maxHeapifyWithNumbers:numbers start:i end:(int)numbers.count - 1];
    }
    //先将第一个元素和已排好元素前一位做交换,再重新调整,直到排序完毕
    for (int i = (int)numbers.count - 1; i > 0; i--) {
        [numbers exchangeObjectAtIndex:0 withObjectAtIndex:i];
        [self maxHeapifyWithNumbers:numbers start:0 end:i - 1];
    }
    NSLog(@"%@",numbers);
}

//调用
NSMutableArray *array = [NSMutableArray arrayWithObjects:@(10),@(4),@(8),@(99),@(16),@(19),@(3), nil];
[self heapSortWithNumbers:array];
  • 时间复杂度

最好、最坏和平均时间复杂度都为O(nlogn)。

  • 算法稳定性

不稳定的排序算法

提供一个他人的更详细的解读堆排序

你可能感兴趣的:(堆排序算法-OC实现)