zoukankan      html  css  js  c++  java
  • 算法之排序——个人笔记

    排序
        排序算法的稳定性:当序列中有相同的数据量,算法会不会改变这两个数据的前后位置。
        冒泡排序:是一种稳定排序,在排序过程中可以监测到数据是否已经有序,可以立既停止,如果待排序的数据基本有序,则冒泡的效率是非常高的。相关参考:https://baike.baidu.com/item/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F/4602306?fr=aladdin
        插入排序:当一列已经有序,再有加入的数据时,适合使用插入排序。相关参考:https://baike.baidu.com/item/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/7214992?fr=aladdin
        选择排序:是冒泡排序的一种变种,但是它没有冒泡对数据有序性的敏感,但它在排序过程中比较冒泡要少了很多数据交换,因此数据比较混乱的情况下要比冒泡要快。相关参考:https://baike.baidu.com/item/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F/9762418?fr=aladdin
        快速排序:一种基于交换的算法,相关参考:https://baike.baidu.com/item/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/369842?fromtitle=%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F&fromid=2084344&fr=aladdin

        堆排序
            首先把数据当作完全二叉树,然后保证根结点最大,然后把根结点与最后一个元素交换,然后再调整二叉树(逐渐减少数组),让根依然保持最大,重复上次操作。相关参考:https://baike.baidu.com/item/%E5%A0%86%E6%8E%92%E5%BA%8F/2840151?fr=aladdin
        归并排序
            不交换数据,但需要借助额外的空间,用作临时的存储空间。

    算法的时间复杂度
        注意:时间复杂度并不是指算法运行所需要的时间,而是算法执行的次数。
        冒泡排序:O(N),O(N^2)
        插入排序:O(N),O(N^2)
        选择排序:O(N^2)
        快速排序:O(nlog2n)
        堆排序:O(nlog2n)
        归并排序:O(nlog2n)

    算法实现如下(C语言):

    #include <stdio.h>
    #include <stdbool.h>
    #include <stdlib.h>
    
    #define swap(a,b) {typeof(a) t=a;a=b;b=t;}    // 宏定义swap
    
    // 冒泡排序
    void bubble_sort(int* arr,int len)    // 传入需要排序的数组及其长度
    {
        for(int i=len-1; i>0; i--)    // 从尾位置往前走
        {
            bool flag = true;    // 如果发现已经有序,则循环结束
            for(int j=0; j<i; j++)    // 从头位置往i的前一个位置走
            {
                if(arr[j] > arr[j+1])    // 如果发现前一个数大于后一个(升序)
                {
                    swap(arr[j],arr[j+1]);    // 就交换它们的数据
                    flag = false;    // 如果存在交换,则置flag为false
                }
            }
            if(flag) break;    // 因为发生交换,所以还没有排好序
        }
    }
    
    // 插入排序
    void insert_sort(int* arr,int len)
    {
        for(int i=1; i<len; i++)    // 从1开始(因为j=i-1)
        {
            int index = -1;    // 记录要插入的位置
            int t = arr[i];    // 临时变量存储arr[i]
            for(int j=i-1; j>=0; j--)    // 从i的前一个位置走到0
            {
                if(t < arr[j])    // 如果前面的数大于临时变量t
                {
                    arr[j+1] = arr[j];    // 元素后移
                    index = j;    // 记录其下标
                }
            }
            if(index != -1)
                arr[index] = t;    // 将临时变量插入到最远位置
        }
    }
    
    // 选择排序
    void select_sort(int* arr,int len)
    {
        for(int i=len-1; i>0; i--)    // 从尾开始往前
        {
            int max = i;    // 存储最大数的坐标
            for(int j=0; j<i; j++)    // 从头开始往i-1的位置走
            {
                if(arr[j] > arr[max])    // 查找最大值
                    max = j;    //记录下标
            }
            swap(arr[i],arr[max]);    // 当前值和最大值进行交换
        }
    }
    
    void _quick_sort(int* arr,size_t left,size_t right)
    {
        if(left >= right) return;    // 左下标和右下标相遇或左下标在右下标的右边,排序完成
        int pi = (left+right)/2; //计算标杆的下标
        int pv = arr[pi];    // 备份标杆的值
        int l = left, r = right;    // 备份左右下标
        while(l < r)    // 左右下标相遇时结束
        {
            while(l < pi && arr[l] <= pv) l++;    // 在标杆的左边寻找比它大的数据
            if(l < pi)    // 如果没有超出范围,说明找到比标杆大的值
            {
                arr[pi] = arr[l];    // 与标杆交换位置,并记录新的标杆下标
                pi = l;
            }
            while(pi < r && arr[r] >= pv) r--;    // 
            if(pi < r)    // 如果没有超出范围,说明找到比标杆小的值
            {
                arr[pi] = arr[r];
                pi = r;
            }
            arr[pi] = pv;    // 还原标杆的值
            if(pi-left > 1) _quick_sort(arr,left,pi-1);    // 递归
            if(right-pi > 1) _quick_sort(arr,pi+1,right);
    
        }
    }
    
    // 快速排序
    void quick_sort(int* arr,size_t len)
    {
        _quick_sort(arr,0,len-1);
    }
    
    void create_heap(int* arr,size_t root,size_t len)
    {
        if(root >= len) return;
        int left = root*2+1;    // 左子树的位置
        int right = root*2+2;    // 右子树的位置
    
        create_heap(arr,left,len);    // 递归
        create_heap(arr,right,len);
    
        int max = root;    // 设当前根结点为最大值
        if(left < len)
        {
            if(arr[left] > arr[max])    // 如果当前根的值大于max中的值
                max = left;    // 将此位置赋给max
        }
        if(right < len)
        {
            if(arr[right] > arr[max])    // 同理
                max = right;
        }
        if(max != root)    // 如果被修改过
            swap(arr[max],arr[root]);    // 交换当前根与最大值
    }
    
    // 堆排序
    void heap_sort(int* arr,size_t len)
    {
        for(int i=0; i<len; i++)
        {
            create_heap(arr,0,len-i);
            swap(arr[0],arr[len-i-1]);
        }
        //show_arr(arr,10);
    }
    
    // 归并排序
    void merge(int* arr,size_t left,size_t pi,size_t right,int* temp)
    {
        int i = left,j = pi+1,k = left;
        // 外部合并 (临时变量是外部提供的)
        while(i<=pi && j<=right)
        {
            if(arr[i] < arr[j])
                temp[k++] = arr[i++];
            else
                temp[k++] = arr[j++];
        }
        while(i<=pi) temp[k++] = arr[i++];
        while(j<=right) temp[k++] = arr[j++];
        for(int i=left; i<=right; i++)
        {
            arr[i] = temp[i];
        }
    }
    
    void _merge_sort(int* arr,size_t left,size_t right,int* temp)
    {
        if(left >= right) return;
        int pi = (left+right)/2;
        _merge_sort(arr,left,pi,temp);
        _merge_sort(arr,pi+1,right,temp);
        merge(arr,left,pi,right,temp);
    }
    
    void merge_sort(int* arr,size_t len)
    {    // 把元素差分成1个个,然后标杆左右两侧进行2块2块的比较
        int temp[len];
        _merge_sort(arr,0,len-1,temp);
    }
    
    void show_arr(int* arr,size_t len)
    {
        for(int i=0; i<len; i++)
        {
            printf("%d ",arr[i]);
        }
    }
    
    int main()
    {
        int arr[10],arr1[10],arr2[10];
        for(int i=0; i<10; i++)
        {
            arr[i] = rand() % 50;
            arr1[i] = rand() % 50;
            arr2[i] = rand() % 50;
        }
        printf("原序列arr:");
        show_arr(arr,10);
    /*
        printf("
    原序列arr1:");
        show_arr(arr1,10);
    
        printf("
    原序列arr2:");
        show_arr(arr2,10);
        printf("
    ");
    
        printf("
    冒泡排序:");
        bubble_sort(arr,10);
        show_arr(arr,10);
        printf("
    插入排序:");
        insert_sort(arr1,10);
        show_arr(arr1,10);
        printf("
    选择排序:");
        select_sort(arr2,10);
        show_arr(arr2,10);
    
        quick_sort(arr2,10);
        show_arr(arr2,10);
    */
    
    //    heap_sort(arr,10);
        merge_sort(arr,10);
        printf("
    ");
        show_arr(arr,10);
    }

    #include <stdbool.h>#include <stdlib.h>
    #define swap(a,b) {typeof(a) t=a;a=b;b=t;}    // 宏定义swap
    // 冒泡排序void bubble_sort(int* arr,int len)    // 传入需要排序的数组及其长度{for(int i=len-1; i>0; i--)    // 从尾位置往前走{bool flag = true;    // 如果发现已经有序,则循环结束for(int j=0; j<i; j++)    // 从头位置往i的前一个位置走{if(arr[j] > arr[j+1])    // 如果发现前一个数大于后一个(升序){swap(arr[j],arr[j+1]);    // 就交换它们的数据flag = false;    // 如果存在交换,则置flag为false}}if(flag) break;    // 因为发生交换,所以还没有排好序}}
    // 插入排序void insert_sort(int* arr,int len){for(int i=1; i<len; i++)    // 从1开始(因为j=i-1){int index = -1;    // 记录要插入的位置int t = arr[i];    // 临时变量存储arr[i]for(int j=i-1; j>=0; j--)    // 从i的前一个位置走到0{if(t < arr[j])    // 如果前面的数大于临时变量t{arr[j+1] = arr[j];    // 元素后移index = j;    // 记录其下标}}if(index != -1)arr[index] = t;    // 将临时变量插入到最远位置}}
    // 选择排序void select_sort(int* arr,int len){for(int i=len-1; i>0; i--)    // 从尾开始往前{int max = i;    // 存储最大数的坐标for(int j=0; j<i; j++)    // 从头开始往i-1的位置走{if(arr[j] > arr[max])    // 查找最大值max = j;    //记录下标}swap(arr[i],arr[max]);    // 当前值和最大值进行交换}}
    void _quick_sort(int* arr,size_t left,size_t right){if(left >= right) return;    // 左下标和右下标相遇或左下标在右下标的右边,排序完成int pi = (left+right)/2; //计算标杆的下标int pv = arr[pi];    // 备份标杆的值int l = left, r = right;    // 备份左右下标while(l < r)    // 左右下标相遇时结束{while(l < pi && arr[l] <= pv) l++;// 在标杆的左边寻找比它大的数据if(l < pi)// 如果没有超出范围,说明找到比标杆大的值{arr[pi] = arr[l];// 与标杆交换位置,并记录新的标杆下标pi = l;}while(pi < r && arr[r] >= pv) r--;// if(pi < r)// 如果没有超出范围,说明找到比标杆小的值{arr[pi] = arr[r];pi = r;}arr[pi] = pv;    // 还原标杆的值if(pi-left > 1) _quick_sort(arr,left,pi-1);    // 递归if(right-pi > 1) _quick_sort(arr,pi+1,right);
    }}
    // 快速排序void quick_sort(int* arr,size_t len){_quick_sort(arr,0,len-1);}
    void create_heap(int* arr,size_t root,size_t len){if(root >= len) return;int left = root*2+1;    // 左子树的位置int right = root*2+2;    // 右子树的位置
    create_heap(arr,left,len);    // 递归create_heap(arr,right,len);
    int max = root;    // 设当前根结点为最大值if(left < len){if(arr[left] > arr[max])    // 如果当前根的值大于max中的值max = left;    // 将此位置赋给max}if(right < len){if(arr[right] > arr[max])    // 同理max = right;}if(max != root)    // 如果被修改过swap(arr[max],arr[root]);    // 交换当前根与最大值}
    // 堆排序void heap_sort(int* arr,size_t len){for(int i=0; i<len; i++){create_heap(arr,0,len-i);swap(arr[0],arr[len-i-1]);}//show_arr(arr,10);}
    // 归并排序void merge(int* arr,size_t left,size_t pi,size_t right,int* temp){int i = left,j = pi+1,k = left;// 外部合并 (临时变量是外部提供的)while(i<=pi && j<=right){if(arr[i] < arr[j])temp[k++] = arr[i++];elsetemp[k++] = arr[j++];}while(i<=pi) temp[k++] = arr[i++];while(j<=right) temp[k++] = arr[j++];for(int i=left; i<=right; i++){arr[i] = temp[i];}}
    void _merge_sort(int* arr,size_t left,size_t right,int* temp){if(left >= right) return;int pi = (left+right)/2;_merge_sort(arr,left,pi,temp);_merge_sort(arr,pi+1,right,temp);merge(arr,left,pi,right,temp);}
    void merge_sort(int* arr,size_t len){// 把元素差分成1个个,然后标杆左右两侧进行2块2块的比较int temp[len];_merge_sort(arr,0,len-1,temp);}
    void show_arr(int* arr,size_t len){for(int i=0; i<len; i++){printf("%d ",arr[i]);}}
    int main(){int arr[10],arr1[10],arr2[10];for(int i=0; i<10; i++){arr[i] = rand() % 50;arr1[i] = rand() % 50;arr2[i] = rand() % 50;}printf("原序列arr:");show_arr(arr,10);/*printf(" 原序列arr1:");show_arr(arr1,10);
    printf(" 原序列arr2:");show_arr(arr2,10);printf(" ");
    printf(" 冒泡排序:");bubble_sort(arr,10);show_arr(arr,10);printf(" 插入排序:");insert_sort(arr1,10);show_arr(arr1,10);printf(" 选择排序:");select_sort(arr2,10);show_arr(arr2,10);
    quick_sort(arr2,10);show_arr(arr2,10);*/
    //heap_sort(arr,10);merge_sort(arr,10);printf(" ");show_arr(arr,10);}

  • 相关阅读:
    CF1454F Array Partition
    leetcode1883 准时抵达会议现场的最小跳过休息次数
    leetcode1871 跳跃游戏 VII
    leetcode1872 石子游戏VIII
    CF1355C Count Triangles
    CF1245D Shichikuji and Power Grid
    CF1368C Even Picture
    CF1368D AND, OR and square sum
    CF1395C Boboniu and Bit Operations
    SpringBoot和开发热部署
  • 原文地址:https://www.cnblogs.com/ikaros-521/p/11224484.html
Copyright © 2011-2022 走看看