zoukankan      html  css  js  c++  java
  • C++ 排序算法

    C++ 常见排序算法

    /*! @brief 冒泡排序
    *
    * 算法之原理: 相邻的数据进行两两比较,小数放在前面,大数放在后面, 
    *              这样一趟下来,最小的数就被排在了第一位,第二趟也是如此,如此类推,直到所有的数据排序完成。 
    
    * 时间复杂度: 平均 O(n^2) 最坏 O(n^2) 
    
    * 空间复杂度: O(1) 
    
    * 算法稳定性: 稳定 
    
    * @param nums the array to sort
    */
    void CSortAlgo::bubble_sort(vector<int> &nums)
    {
        int len = nums.size();
        for (int i = 0; i < len - 1; i++)
        {
            for (int j = len - 1; j > i; j--)
            {
                if (nums[j] < nums[j - 1])
                {
                    int temp = nums[j];
                    nums[j] = nums[j - 1];
                    nums[j - 1] = temp;
                }
            }
        }
    }
    
    
    /*! @brief 选择排序
    
    * 算法之原理: 先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,
    *              然后,再从剩余未排序元素中继续寻找最小(大)元素,
    *              然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
    
    * 时间复杂度: 平均 O(n^2) 最坏 O(n^2) 
    
    * 空间复杂度: O(1) 
    
    * 算法稳定性: 不稳定 
    
    * @param nums the array to sort
    */
    void CSortAlgo::select_sort(vector<int> &nums)
    {
        int len = nums.size();
        for (int i = 0; i < len; i++)
        {
            int index = i;
            for (int j = i + 1; j < len; j++)
            {
                if (nums[j] < nums[index])
                    index = j;
            }
            if (index != i)
            {
                int temp = nums[i];
                nums[i] = nums[index];
                nums[index] = temp;
            }
        }
    }
    
    
    /*! @brief 插入排序
    
     * 算法之原理: 将数据分为两部分,有序部分与无序部分,一开始有序部分包含第1个元素,
     *               依次将无序的元素插入到有序部分,直到所有元素有序。
     *               插入排序又分为直接插入排序、二分插入排序、链表插入等,这里只讨论直接插入排序。
    
     * 时间复杂度: 平均 O(n^2) 最坏 O(n^2) 
    
     * 空间复杂度: O(1) 
    
     * 算法稳定性: 稳定 
    
     * @param nums the array to sort
    */
    void CSortAlgo::insert_sort(vector<int> &nums)
    {
        int len = nums.size();
        for (int i = 1; i < len; i++)
        {
            int j = i - 1;
            int k = nums[i];
            while (j > -1 && k < nums[j])
            {
                nums[j + 1] = nums[j];
                j--;
            }
            nums[j + 1] = k;
        }
    }
    
    
    /*! @brief 快速排序
     * @details
     * 算法之原理: 快速排序是目前在实践中非常高效的一种排序算法。
     *               通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
     *               然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
    
     * 时间复杂度: 平均 O(nlogn) 最坏 O(n^2) 
    
     * 空间复杂度: O(logn) 
    
     * 算法稳定性: 不稳定 
    
     * @param nums the array to sort
     * @param left 
     * @param right 
    */
    void CSortAlgo::quick_sort(vector<int> &nums, int left, int right)
    {
        int len = nums.size();
        if (left < right)
        {
            int i = left, j = right, target = nums[left];
            while (i < j)
            {
                while (i < j && nums[j] > target)
                    j--;
                if (i < j)
                    nums[i++] = nums[j];
    
                while (i < j && nums[i] < target)
                    i++;
                if (i < j)
                    nums[j] = nums[i];
            }
            nums[i] = target;
            quick_sort(nums, left, i - 1);
            quick_sort(nums, i + 1, right);
        }
    }
    
    /*! @brief 归并排序
    
     * 算法之原理: 归并排序具体工作原理如下(假设序列共有n个元素):
     * 将序列每相邻两个数字进行归并操作(merge),形成floor(n / 2)个序列,排序后每个序列包含两个元素
     * 将上述序列再次归并,形成floor(n / 4)个序列,每个序列包含四个元素
     * 重复步骤2,直到所有元素排序完毕。
    
     * 时间复杂度: 平均 O(nlogn) 最坏 O(nlogn) 
    
     * 空间复杂度: O(1) 
    
     * 算法稳定性: 稳定 
    
     * @param nums the array to sort
     * @note 如果是使用链表的实现的话,空间复杂度可以达到O(1),
     * 但如果是使用数组来存储数据的话,在归并的过程中,需要临时空间来存储归并好的数据,所以空间复杂度为O(n)
    */
    void CSortAlgo::merge_sort(vector<int> &nums, vector<int> &nums_temp, int start_index, int end_index)
    {
        if (start_index < end_index)
        {
            int mid_index = (start_index + end_index) / 2;
            merge_sort(nums, nums_temp, start_index, mid_index);
            merge_sort(nums, nums_temp, mid_index + 1, end_index);
            merge(nums, nums_temp, start_index, mid_index, end_index);
        }
    }
    
    void CSortAlgo::merge(vector<int> &nums, vector<int> &nums_temp, int start_index, int mid_index, int end_index)
    {
        // 将有二个有序数列nums[start_index...mid_index]和nums[mid_index...end_index]合并。  
        int i = start_index, j = mid_index + 1;
        int k = 0;
        while (i < mid_index + 1 && j < end_index + 1)
        {
            if (nums[i] > nums[j])
                nums_temp[k++] = nums[j++];
            else
                nums_temp[k++] = nums[i++];
        }
        while (i < mid_index + 1)
            nums_temp[k++] = nums[i++];
        while (j < end_index + 1)
            nums_temp[k++] = nums[j++];
    
        for (i = 0, j = start_index; j < end_index + 1; i++, j++)
            nums[j] = nums_temp[i];
    }
    
    /*! @brief 堆排序
    
    * 算法之原理: (以最大堆为例)
    *            1. 先将初始数据R[1..n]建成一个最大堆,此堆为初始的无序区
    *            2. 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,
    *            由此得到新的无序区R[1..n - 1]和有序区R[n],且满足R[1..n - 1].keys≤R[n].key
    *            3. 由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n - 1]调整为堆。
    *            重复2、3步骤,直到无序区只有一个元素为止。
    
    * 时间复杂度: 平均 O(nlogn) 最坏 O(nlogn) 
    
    * 空间复杂度: O(1) 
    
    * 算法稳定性: 不稳定 
    
    * @param nums the array to sort
    */
    void CSortAlgo::heap_sort(vector<int> &nums)
    {
        int len = nums.size();
        int i;
        // 调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素
        for (int i = len / 2 - 1; i >= 0; i--)
        {
            heap_adjust(nums, i, len);
        }
    
        for (i = len - 1; i > 0; i--)
        {
            // 将第1个元素与当前最后一个元素交换,保证当前的最后一个位置的元素都是现在的这个序列中最大的
            int temp = nums[0];
            nums[0] = nums[i];
            nums[i] = temp;
            // 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
            heap_adjust(nums, 0, i);
        }
    }
    
    /*!
     * 将数组arr构建大根堆
     * @param nums 待调整的数组
     * @param i    待调整的数组元素的下标
     * @param len  数组的长度
     */
    void CSortAlgo::heap_adjust(vector<int> &nums, int i, int len)
    {
        int child;
        int temp;
        for (; 2 * i + 1 < len; i = child)
        {
            child = 2 * i + 1;  // 子结点的位置 = 2 * 父结点的位置 + 1
                                // 得到子结点中键值较大的结点
            if (child < len - 1 && nums[child + 1] > nums[child])
                child++;
            // 如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点
            if (nums[i] < nums[child])
            {
                temp = nums[i];
                nums[i] = nums[child];
                nums[child] = temp;
            }
            else
                break;
        }
    }
  • 相关阅读:
    [编织消息框架][设计协议]bit基础
    android studio最简单的包名修改方法
    MySQL之四——浅谈 DML、DDL、DCL的区别
    MySQL之三——SQL优化
    MySQL之二——MySQL缓存机制
    MySQL之一——基础语法详解
    游戏测试相关内容
    第一篇博客
    mybatis中union可以用if判断连接,但是<select>中第一个select语句不能被if判断,因此可以从dual表中查询null来凑齐。union如果使用order by排序,那么只能放在最后一个查询语句的位置,并且不能带表名。
    博客园
  • 原文地址:https://www.cnblogs.com/VVingerfly/p/7401288.html
Copyright © 2011-2022 走看看