一生一芯系列笔记: 预学习——复习C语言(练习33笔记, 冒泡排序和归并排序)

暮雨٩(๑˃̵ᴗ˂̵๑)۶终将落下 发布于 2025-01-09 662 次阅读


简介

冒泡排序和归并排序是两种常见的排序算法,它们在排序思想和实现方式上有很大的不同。冒泡排序通过重复遍历待排序的列表,每次遍历都将当前待排序的列表中的最大值或者最小值“冒泡”到正确的位置,其算法复杂度为$$O(n^2)$$。归并排序则是基于分而治之的思想,将待排序的数组分为左右两边,然后分别排序后合并,其中涉及到递归操作,算法复杂度为$$O(nlog(n))$$。

冒泡排序

算法原理

我们基于以下思想,当我们遍历一遍数组,我们就可以找到整个数组中的最小值,我们将这个最小值和数组第一个交换位置,然后开启下一轮遍历。此时,我们知道这一轮遍历可以排除掉第一个元素了,因为第一个元素的值必定比其它值都小。重复这个过程我们可以一直到列表的最后一个元素。

代码

我们基于练习32部分完成的链表,实现冒泡排序算法

void swap_node(ListNode* a,ListNode *b){
    void *c = a->value;
    a->value = b->value;
    b->value = c;
}
int List_bubble_sort(List *list, List_compare cmp)
{
    if(list->count < 2)
        return 0;
    for(ListNode *nodeA = list->first;nodeA != list->last ; nodeA=nodeA->next){
        for(ListNode *nodeB = nodeA->next;nodeB != NULL;nodeB=nodeB->next){
            if(cmp(nodeB->value,nodeA->value) < 1){
                swap_node(nodeA,nodeB);
            }
        }
    }
    return 0;
}

归并排序

算法原理

归并排序并不像冒泡排序那样便于理解,因为其中涉及到了递归的思想。
我们将一个数组分为左右两个部分,将左右两个部分排序好(我们假设我们已经完成了归并排序算法,所以这里我们对左右两边分别调用归并排序算法即可)后合并到一起,同时我们在函数入口判断,当传入的数组大小为0或者1时,我们直接将该数组返回。
用于合并左右两边的代码原理为,我们先跑一个循环,循环退出条件为两个数组其中一个为空。在循环中我们比较两个数组的首元素,将较小的那个压入result数组中。最后我们将剩下的数组接到result数组的最后。

代码实现

这里我们还是和前面一样,通过C语言实现。

List* merge_list(List* left, List* right,List_compare cmp){
    List* result = List_create();
    while(left->first && right->first){
        if(cmp(left->first->value,right->first->value) < 0){
            List_push(result,List_shift(left));
        } else {
            List_push(result,List_shift(right));
        }
    }
    while(left->first){
        List_push(result,List_shift(left));
    }
    while(right->first){
        List_push(result,List_shift(right));
    }
    return result;
}
List *List_merge_sort(List *list, List_compare cmp)
{
    if(list->count<2) return list;
    int left = list->count/2;
    int right = list->count - left;
    List * left_list = List_create();
    List * right_list = List_create();
    for(int i=0;i<right;i++){
        List_push(right_list,List_pop(list));
    }
    left_list = list;
    return merge_list(List_merge_sort(left_list,cmp),List_merge_sort(right_list,cmp),cmp);
}