首页 > 编程语言 >排序算法

排序算法

时间:2023-09-04 20:24:21浏览次数:44  
标签:target nums int 元素 算法 排序 inc

排序

参考:视频

交换排序:冒泡排序和快速排序

冒泡:比较两个元素,比较大就往后放,那么每一次都会将一个最大的元素放在末尾,所以下一次就不需要遍历最后哪些排完序的元素。
时间复杂度:O(n^2)
稳定

#include<vector>
#include<iostream>
using namespace std;

void blue_blue(vector<int>& nums){
    
    for(int i=0;i<nums.size()-1;i++){ // 每一轮将完成一个元素的排序,最多只需要执行nums.size()-1轮。
        bool sign= false;
        for(int j=0;j<=nums.size()-2-i;j++){// 完成排序的元素不会再进行比较,所以“-i”
            if(nums[j]> nums[j+1]) {
                sign =true;
                swap(nums[j],nums[j+1]);
            }   
        }
        if(!sign) return; // 本轮没有发生交换,则代表已经排序完成了
    }
    return ;
}

int main(){
    int number;
    vector<int> nums;
    cin>> number;

    for(int i=0;i<number;i++){
        int tmp;
        cin>> tmp;
        nums.push_back(tmp);
    }
    blue_blue(nums);
    for(auto num:nums){
        cout<< num << endl;;
    }

    return 0;
}

快速排序:选择第一个元素作为轴,如果将右边比轴小的元素放入轴所在的位置,然后将左边比轴大的元素放入右边上次空出来的位置,如此往复,直到左右指针相遇,此时将轴放入相遇的位置。
在最糟情况下,其运行时间为O(n^2)。在平均情况下,快速排序的运行时间为O(nlogn)。
【注】如果元素和轴相等的话,交不交换都一样。
不稳定

void fast_sort(vector<int>& nums,int start, int end){
    if(end<=start) return ;
    int tmp =nums[start];
    int left =start,right = end;

    while(left!=right){
        while(left!=right && nums[right]>= tmp) right--;
        if(left!=right) swap(nums[right],nums[left++]);
        else break;

        
        while(left!=right && nums[left]<= tmp) left++;
        if(left!=right) swap(nums[left],nums[right--]);
        else break;
    }
    nums[left] =tmp;
    fast_sort(nums,start,left-1);
    fast_sort(nums,left+1,end);
    return ;    
}

插入排序:直接插入、折半插入和希尔排序

直接插入:在排好序的数组中,从右往左查找第一个小于等于当前元素的元素。没找到时,每次查找都向后移动一个位置;找到时将元素放在空位中。
稳定。

void insert_direct(vector<int>& nums){
    if(nums.size()<2) return;
    for(int i=1;i<nums.size();i++){
        for(int j=i;j>=1;j--){
            if(nums[j] >= nums[j-1]) 
                break;
            else 
                swap(nums[j],nums[j-1]);
        }
    }

    return ;    
}

折半插入:查找时使用折半查找。折半查找见数组章节.
折半插入并没有比直接插入快。

int search(const vector<int> nums,int target,int start, int end){
    int left = start; // target不存在时,left要么指向第一个大于target的元素,要么指向小于target的元素。
    int right=end;    // target不存在时,right要么指向最后一个小于target的元素,要么指向大于target的元素。
                      // nums[mid]==target时,移动left且target存在,则最终left-1指向最后一个target。
                      // nums[mid]==target时,移动right且target存在,则最终right+1指向第一个target

    while(right>=left){
        int mid = (right+left)/2; 
        if(nums[mid]<=target){
            left = mid+1;
        }
        else right = mid-1;
    }

    return left;
}

void half_direct(vector<int>& nums){
    if(nums.size()<2) return;
    int j=0;
    for(int i=1;i<nums.size();++i){
        int index = search(nums,nums[i],0,i-1);
        int tmp = nums[i];
        for(j=i;j>index;--j)  swap(nums[j-1],nums[j]);
    }

    return ;    
}

希尔排序:最坏的时间复杂度为O(n^2)
不稳定

void shell_sort(vector<int>& arr)
{
    int i, j, inc, key;
    // 初始增量:len/2,每一趟之后除以二
    for (inc = arr.size() / 2; inc > 0; inc /= 2) // inc代表跨度
    {
        // 每一趟采用插入排序
        for (i = inc; i < arr.size(); i++) // 
        {
            key = arr[i];
            for (j = i; j >= inc && key < arr[j - inc]; j -= inc)
                arr[j] = arr[j - inc];
            arr[j] = key;
        }
    }
}

上面代码中:i代表跨度为inc的第二个点,而i加一以后跨度还是inc,即所有距离为五的元素都进行了希尔排序,而普通的希尔排序中只对其中的几个元素进行排序

选择:

  • 简单选择排序:每次扫描整个数组找出最小的元素,然后将最小的元素和最前面元素进行交换。和冒泡排序一样,每一轮都完成一个元素的排序。
    时间复杂度:
  • 堆排序:

简单选择排序

void simple_selection_sort(vector<int>& nums){
    for(int i=0;i <nums.size();i++){
        int minE = i;
        for(int j=i+1; j<nums.size();j++){
            if(nums[j]< nums[minE]) minE=j;
        }
        swap(nums[minE],nums[i]);
    }

    return ;    
}

堆排序(大顶堆和小顶堆)

整数除法代表结果向下取整。

大顶堆实现升序排列:

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;

// 将节点i向下调整
void heapify(vector<int>& nums,int n, int i){ // 从节点i开始向下调整堆,堆的是从nums[0]到nums[n-1]
    int largest =i;
    int lson = 2*i + 1;
    int rson = 2*i + 2;
    if(lson<n && nums[largest]< nums[lson]) largest = lson; // 如果构建小顶堆,只需要将这里小于号变为大于号。
    if(rson<n && nums[largest]< nums[rson]) largest = rson; // 如果构建小顶堆,只需要将这里小于号变为大于号。
    

    if(largest!=i) {
        swap(nums[largest],nums[i]);
        heapify(nums,n,largest); // 孩子节点可能也许要向下调整
    }
}

void heap_sort(vector<int> &nums){
    // 将乱序的堆变成大顶堆
    for(int i=(nums.size()-2)/2;i>=0;i--)
        heapify(nums,nums.size(),i);

    // 排序
    for(int i = nums.size()-1;i>0;i--){
        swap(nums[i],nums[0]); // 将堆顶元素(最大值)放在数组末尾i,从而实现排序
        heapify(nums,i,0); // 调整元素nums[0]~nums[i-1]
    }
    
}


int main(){
    int number;
    vector<int> nums;
    cin>> number;

    for(int i=0;i<number;i++){
        int tmp;
        cin>> tmp;
        nums.push_back(tmp);
    }
    heap_sort(nums);
    for(auto num:nums){
        cout<< num << endl;;
    }

    return 0;
}

大顶堆用于升序排序,大顶堆用于降序排序。

标签:target,nums,int,元素,算法,排序,inc
From: https://www.cnblogs.com/codingbigdog/p/17677989.html

相关文章

  • 复杂性分析与算法设计:解锁计算机科学的奥秘
    文章目录算法复杂性分析的基本概念时间复杂度空间复杂度常见的算法设计策略1.分治法2.贪心法3.动态规划算法设计的实际应用1.网络路由2.图像处理3.人工智能算法的选择和性能分析结论......
  • Lnton羚通视频分析算法平台OpenCV-Python 教程 Hough直线变换
    OpenCVPythonHough直线变换霍夫直线变换(HoughTransform)是一种在图像中检测直线的技术。它可以帮助我们从图像中鲜明地检测出直线段,并且对于噪声和不完整的线段也有较好的鲁棒性。霍夫直线变换的基本思想是将直线表示为参数空间中的曲线,通过统计参数空间中的交点来检测直线。以下......
  • 排序算法知识点和常见面试题
    查找和排序算法知识点和常见面试题查找二分查找排序算法知识点冒泡排序插入排序选择排序快速排序二分思维+递归思维#include<stdio.h>intFindPos(int*a,intlow,inthigh);voidQuickSort(int*a,intlow,inthigh);intmain(void){ inta[6]={-2,1,......
  • 文心一言 VS 讯飞星火 VS chatgpt (86)-- 算法导论8.2 3题
    三、用go语言,假设我们在COUNTING-SORT的第10行循环的开始部分,将代码改写为:10forj=1toA.length试证明该算法仍然是正确的。它还稳定吗?文心一言:首先,让我们先明确COUNTING-SORT算法的基本思想。COUNTING-SORT是一种线性时间复杂度的排序算法,它适用于对一定范围内的整数......
  • 文心一言 VS 讯飞星火 VS chatgpt (86)-- 算法导论8.2 3题
    三、用go语言,假设我们在COUNTING-SORT的第10行循环的开始部分,将代码改写为:10forj=1toA.length试证明该算法仍然是正确的。它还稳定吗?文心一言:首先,让我们先明确COUNTING-SORT算法的基本思想。COUNTING-SORT是一种线性时间复杂度的排序算法,它适用于对一定范围内的......
  • 算法题 逃离迷宫
     题目描述:你在一个地下迷宫中找到了宝藏,但是也触发了迷宫机关,导致迷宫将在T分钟后坍塌,为此你需要在T分钟内逃离迷宫,你想知道你能不能逃离迷宫。迷宫是一个边长为m的正方形,其中"S"表示你所在的位置,"E"表示迷宫出口,"."是可以随意走动的区域,"#"是不可穿行的墙壁,每次你可以耗费1分钟在......
  • Java 快速排序
    思路通过一趟排序将无序数组划分成独立的两部分,其中一部分的所有元素比另外一部分的所有元素都要小,然后再按此方法对这两部分元素分别进行快速排序,整个排序过程可以递归进行,以此达到整个无序数组变成有序数组的目的。快速排序主要分为以下步骤:从无序数组中取出一个元素作为基......
  • Java 归并排序
    思路数组排序主要分为两个部分:划分数组和归并排序。划分数组:将待排序的无序数组分为左右两个部分,如果无序数组的起始元素下标为first,最后一个元素的下标为last,那么左右两部分之间的临界点下标mid=(first+last)/2,这两部分分别是arr[first…mid]和arr[mid+1…last];将上......
  • Java 堆排序
    思路从最后的非叶子节点开始,从后向前构建一个堆(大顶堆/小顶堆);即最后的非叶子节点和其下的叶子节点构成一个大顶堆,然后再找前面一个非叶子节点继续此时根节点是最大的数据,然后将根节点和最后一位进行交换交换后,排除最后一位最大值,再从根节点开始构建大顶堆重复2,3步骤代码......
  • Bresenham算法画圆
    目录问题背景Bresenham算法画圆算法推演算法步骤算法程序参考问题背景如何在屏幕上绘制一个圆?可以先看看圆的特性,根据其特性决定如何绘制。。圆的特性圆定义:所有距离中心位置(xc,yc)为给定值r的点集。圆的方程:\[(x-x_c)^2+(y-y_c)^2=r^2\tag{1}\]根据圆的方程绘制圆......