排序算法详解1

排序算法详解1

一、前言

最近一直忙着刷题,今天继续来更新啦~今天,是排序算法

二、排序算法

2.1 概述

我们拿到一个数据结构,就会就其中进行一定的操作,比如:让数据的关键字有序存放

这里的序,找数据的唯一标识key(按照?排序),默认是从小到大

2.2 特性

  • 内排序、外排序

    内,指内存。程序是可以直接寻址的。

    数据量很大时,内存存不下,就需要借助外存。排序最终影响的是外存存储的数据。

    目前阶段主要是内存排序

  • 就地排序、非就地排序

    cpp 复制代码
    void fun(int *data, int num);				// 就地排序
    int *fun(const int *data, int num);			 // 非就地排序
  • 稳定排序、非稳定排序

    当存在数值相等时,往往本在前面的还是在前面,就是相对稳定一些(更具有规律)

2.3 算法评价指标

  • 时间复杂度
  • 空间复杂度

测试框架:准备数据(随机生成)-> 执行排序 -> 验证结果 -> 输出执行时间

2.4 排序算法

2.4.1 插入排序

概述

将数据按照一定的顺序一个一个插入到有有序的表中,最终得到已经排好序的数据

类似玩扑克中的摸牌

插入数组将数组分为两个部分:已排序区和未排序区

方法

  • 直接插入排序

  • 折半插入排序

  • 希尔排序(缩小增量排序)

    先迈大步子,然后不断缩小步长(增量:n / 2, n / 4...)

代码

cpp 复制代码
// 1. 默认第一个元素就是有序,那么从第二个元素开始和前面的有序区的值进行比较
// 2. 待插入的元素i,和已经有序的区域从后往前依次查找
void insertSort(vector<int>& table)
{
    for(int i = 1; i < table.size(); ++i)
    {
        if(table[i] < table[i - 1])
        {
            // 用j的辅助索引来找到待插入元素该放的位置上
            int j = i - 1;
            int temp = table[i];	// 备份
            // 从[0, i - 1]
            while(j >= 0 && table[j] > temp)
            {
                table[j + 1] = table[j];		// 当前已经备份到后一个了
                j--;
            }
            table[j + 1] = temp;
        }
    }
}
// 希尔排序(作了解)
void shellSort(vector<int>& table)
{
    for(int gap = table.size() / 2; gap > 0; gap /= 2)
    {
        for(int i = gap; i < table.size(); ++i)
        {
            Element temp = table[i];
            int j;
            for(int j = i; j >= gap && table[j - gap] > temp; j -= gap)
            {
                table[j] = table[j - gap];
            }
            table[j] = temp;
        }
    }
}

时间复杂度

O(n2n^2n2)

2.4.2 交换排序

方法

  • 冒泡排序

    cpp 复制代码
    // 优化版本1
    // 第一次遍历[0, n - 1), 第二次遍历[0, n - 2)...遍历n - 1次
    void bubbleSortV1(vector<int>& table)
    {
        for(int i = 0; i < table.size() - 1; ++i)
        {
            for(int j = 0; j < table.size() - 1 - i; ++j)
            {
                if(table[j] > table[j - 1])
                {
                    swap(table[j + 1], table[j]);
                }
            }
        }
    }
    // 优化版本2
    // 引入是否交换的标志,当发现某一轮不需要交换,那么就说明已经有序,退出循环
    void bubbleSortV2(vector<int>& table)
    {
        for(int i = 0; i < table.size() - 1; ++i)
        {
            int isSorted = 1;
            for(int j = 0; j < table.size() - 1 - i; ++j)
            {
                if(table[j] > table[j - 1])
                {
                    swap(table[j + 1], table[j]);
                    isSorted = 0;
                }
            }
            if(isSorted)
                break;
        }
    }
    // 优化版本3
    // 引入newIndex标记交换的索引位置,下次冒泡的时候结束位置就是newIndex
    void bubbleSortV3(vector<int>& table)
    {
        int newIndex;
        int n = table.size();
        do
        {
            newIndex = 0;
            for(int i = 0; i < n - 1; ++i)
            {
                if(table[i] > table[i + 1])
                {
                    swap(table[i + 1], table[i]);
                    newIndex = i + 1;
                }
            }
            n = newIndex;
        } while(newIndex > 0);
    }
  • 快速排序

    核心:找犄点pos(返回索引值),pos小的位置上存储的都是比pos位置上的值小

    找犄点的方法(含代码)

    • 双边循环法(双指针)

      cpp 复制代码
      // 解题版
      void quickSort(int arr[], int low, int high)
      {
          if (low < high)
          {
              int i = low, j = high;
              int pivot = arr[low]; // 基准元素
              // 这样low位置就成了一个坑,可以往里面放元素
              while (i < j) {
                  while (i < j && arr[j] > pivot) j--;
                  if (i < j) arr[i++] = arr[j];
                  // 把j位置的元素放到i位置,i++变成1
                  while (i < j && arr[i] <= pivot) i++;
                  if (i < j) arr[j--] = arr[i];
              }
              arr[i] = pivot;
              quickSort(arr, low, i - 1); // 递归排序左子数组
              quickSort(arr, i + 1, high); // 递归排序右子数组
          }
      }
      // 工程版
      static int partitionDouble(vector<int>& table, int startIndex, int endIndex)
      {
          int pivot = startIndex;
          int left = startIndex;
          int right = endIndex;
          // 随机将startIndex和后续的一个随机索引指向的元素进行交换
          while(left != right)
          {
              while(left < right && table[right] > table[pivot])
                  right--;
              while(left < right && tablr[left] <= table[pivot])
                  left++;
              if(left < right)
              	swap(table[right], table[left]);
          }
          swap(table[pivot], table[left]);
          return left;		// 此时,左边和右边相等
      }
      // 用递归思想实现[start, end]区间的排序
      static void quickSort1(vector<int>& table, int startIndex, int endIndex)
      {
          if(startIndex >= endIndex)
              return;
          // 找到犄点
          int pivot = partitionDouble(table, startIndex, int endIndex);
          quickSort1(table, startIndex, pivot - 1);
          quickSort1(table, pivot + 1, endIndex);
      }
      void quickSortV1(vector<int>& table)
      {
          quickSort1(table, 0, table.size() - 1);
      }
    • 单边循环法

      cpp 复制代码
      // 解题版
      void quickSort(int arr[], int low, int high)
      {
          if (low >= high) return;  // 递归终止条件
          int pivot = arr[high];  // 选择最后一个元素作为基准
          int i = low - 1;        // 小于基准的区域的边界
          
          for (int j = low; j < high; j++) {
              if (arr[j] <= pivot) {
                  i++;
                  swap(arr[i], arr[j]);
              }
          }
          
          // 将基准放到正确位置
          swap(arr[i + 1], arr[high]);
          int pivotIndex = i + 1;
          
          // 递归排序左右子数组
          quickSort(arr, low, pivotIndex - 1);
          quickSort(arr, pivotIndex + 1, high);
      }
      // 工程版
      static int partitionSingle(vector<int>& table, int startIndex, int endIndex)
      {
          int temp = table[startIndex];
          int mark = startIndex;
          for(int i = startIndex + 1; i <= endIndex; i++)
          {
              if(table[i] < temp)
              {
                  mark++;
              	swapElement(table[i], table[mark]);
              }
          }
          swap(table[startIndex], table[mark]);
          return mark;
      }
      static void quickSort2(vector<int>& table, int startIndex, int endIndex)
      {
          if(startIndex >= endIndex)
              return;
          // 找到犄点
          int pivot = partitionDouble(table, startIndex, int endIndex);
          quickSort2(table, startIndex, pivot - 1);
          quickSort2(table, pivot + 1, endIndex);
      }
      void quickSortV2(vector<int>& table)
      {
          quickSort2(table, 0, table.size() - 1);
      }

    时间复杂度:O(nlogn)

三、小结

还有许多其他排序算法,敬请期待~

相关推荐
Via_Neo2 小时前
JAVA中对数的表达,将浮点数转为保留指定位数的字符串
java·开发语言
啊我不会诶2 小时前
25CCPC东北邀请赛vp补题
c++·算法
plus4s2 小时前
3月20日(进阶11)
c++·算法
Lzh编程小栈2 小时前
数据结构与算法——单链表超详解(C语言完整实现 + 面试高频题)
c语言·开发语言·面试
沐知全栈开发2 小时前
Shell 函数
开发语言
jyyyx的算法博客2 小时前
【跳跃游戏】题集
算法
2301_816651222 小时前
移动语义在容器中的应用
开发语言·c++·算法
不要秃头的小孩2 小时前
力扣刷题——77. 组合
数据结构·python·算法·leetcode
2401_857918292 小时前
实时数据处理中的C++应用
开发语言·c++·算法