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);}

  • 相关阅读:
    【网络对抗技术】20181234 Exp6 MSF应用基础
    2018-2019-1 20189229 《Linux内核原理与分析》第九周作业
    2018-2019-1 20189229 《Linux内核原理与分析》第八周作业
    2018-2019-1 20189229 《Linux内核原理与分析》第七周作业
    2018-2019-1 20189229《Linux内核原理与分析》第六周作业
    2018-2019-1 20189229 《Linux内核原理与分析》第五周作业
    20189229 张子松 第四周作业
    2018-2019-1 20189229《Linux内核原理与分析》第三周作业
    20189229 张子松 第二周作业
    《Linux内核原理与分析》第一周作业
  • 原文地址:https://www.cnblogs.com/ikaros-521/p/11224484.html
Copyright © 2011-2022 走看看