c/c++常见算法及实现

本文详细介绍了冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序和堆排序等常见的排序算法,分析了它们在不同情况下的时间复杂度和空间复杂度,并提供了相应的C++代码实现。
摘要由CSDN通过智能技术生成

排序算法

平均时间复杂度

最好情况

最坏情况

空间复杂度

稳定性

冒泡排序

O(n2)

O(n)

O(n2)

O(1)

稳定

选择排序

O(n2)

O(n2)

O(n2)

O(1)

不稳定

插入排序

O(n2)

O(n)

O(n2)

O(1)

稳定

希尔排序

O(nlogn)

O(nlog2n)

O(nlog2n)

O(1)

不稳定

归并排序

O(nlogn)

O(nlogn)

O(nlogn)

O(n2)

稳定

快速排序

O(nlogn)

O(nlogn)

O(n2)

O(nlogn)

不稳定

堆排序

O(nlogn)

O(nlogn)

O(nlogn)

O(1)

不稳定

  • 冒泡排序

冒泡排序正如其名,这个算法像是泡泡一样往上升,具体步骤如下:

1.将第一个元素与第二元素作比较,如果前者大于后者则交换。按照这个规则从第一个元素一直遍历到最后一对元素比较完为止。

2.从第二个元素开始按上面规则往后遍历,然后作比较进行交换,每次都至少能将一个值放到后面排好序。

3.不断的重复上述过程,直到没有元素交换为止。

class Solution {
public:
    //冒泡排序
    void BubbleSort(vector<int>& a)
    {
        for(int i=0;i<a.size()-1;i++)
            for(int j=1;j<a.size()-i;j++)
                if(a[j-1]>a[j])
                    swap(a[j-1],a[j]);
    }
    vector<int> MySort(vector<int>& arr) {
        BubbleSort(arr);
        return arr;
    }
};
  • 选择排序

选择排序就是我每一趟排序都找到一个值,放在我当前的所在位置,具体步骤如下:

  1. 首先从下标为 0 开始,遍历一遍数组并找到最小的值,把它放到下标为 0 的位置。

  2. 然后从下标为 1 开始,遍历后续数组并找到后面元素中最小的值,把它放到下标为 1 的位置。

  3. 以此类推,直到最后一趟排序结束。

class Solution {
public:
    //直接选择排序
    void SelectSort(vector<int>& a)
    {
        for(int i=0;i<a.size();i++)
        {
            int min=i;
            for(int j=i;j<a.size();j++)
                if(a[j]<a[min])
                    min=j;
            swap(a[i],a[min]);
        }
    }
    vector<int> MySort(vector<int>& arr) {
        SelectSort(arr);
        return arr;
    }
};
  • 插入排序

插入排序的每趟排序都会将当前的元素与其前面的元素进行排序,步骤如下:

1.从第一个元素开始,因为第一个元素之前没有元素,所以直接认为它是有序的了。

2.找到下一个元素并拿出来,对前面已经排好序的元素进行从后往前的遍历,如果遍历的元素要大于拿出来的元素,则往后移一位。直到遍历的元素小于取出元素或者已经遍历到最开头,遍历结束并将拿出来的元素插入该位置之后。

3.重复上述步骤,直至最后一趟排序结束。

class Solution {
public:
    //插入排序
    void InsertSort(vector<int>& a)
    {
        for(int i=1;i<a.size();i++)
        {
            if(a[i]<a[i-1])
            {
                int tmp=a[i];
                int j=i;
                while(tmp<a[j-1])
                {
                    a[j]=a[j-1];
                    j--;
                }
                a[j]=tmp;
            }
        }
    }
    vector<int> MySort(vector<int>& arr) {
        InsertSort(arr);
        return arr;
    }
};
  • 希尔排序

希尔排序是插入排序的一种更高效的改进版本,算法步骤如下:

  1. 选择一个间隔距离 k ,对元素间隔距离为 k 的序列进行排序,如果存在逆序则进行交换操作。

  2. 缩小 k ,再次进行排序操作。

  3. 重复上述操作,直至 k 小于 1 时停止排序。

class Solution {
public:
    //Shell排序
    void ShellSort(vector<int>& a)
    {
        int h=1;
        while(h<a.size()/3)
            h=3*h+1;
        while(h>=1)
        {
            for(int i=h;i<a.size();i++)
                for(int j=i;j>=h&&a[j]<a[j-h];j-=h)
                    swap(a[j],a[j-h]);
            h/=3;
        }
    }
    vector<int> MySort(vector<int>& arr) {
        ShellSort(arr);
        return arr;
    }
};
  • 归并排序

归并排序采用了分治法的思想,不断将两个有序的序列进行合并从而最终得到整个有序的序列,算法步骤如下:

1、把当前长度为 n 的序列分为两个长度为 n / 2 的子序列,对子序列进行操作。

2、同样对两个子序列进行划分,再分别对其子序列进行划分操作,直至子序列中只有一个元素为止就不再进行划分,而是进行回溯。

3、通过回溯的子序列进行排序操作,我们额外创建一个数组出来,将回溯的两个子序列进行合并操作。

4、一直往上回溯,这样每次得到的两个回溯的子序列都是有序的,可以方便我们进行合并操作,合并的序列也会是有序的。

class Solution {
public:
    //归并排序
    void Merge(vector<int>& a,int l,int r)
    {
        if(l>=r)
            return;
        int m=(l+r)/2;
        Merge(a,l,m);
        Merge(a,m+1,r);
        MergeSort(a,l,m,r);
    }
    void MergeSort(vector<int>& a,int l,int m,int r)
    {
        vector<int>temp;
        int left=l,right=m+1;
        while(left<=m&&right<=r)
            temp.emplace_back(a[left]<=a[right]?a[left++]:a[right++]);
        while(left<=m)
            temp.emplace_back(a[left++]);
        while(right<=r)
            temp.emplace_back(a[right++]);
        for(int j=0;j<temp.size();j++)
            a[l+j]=temp[j];
    }
    vector<int> MySort(vector<int>& arr) {
        Merge(arr,0,arr.size()-1);
        return arr;
    }
};
  • 快速排序

快速排序也是利用了递归思想,算法步骤如下:

  1. 选取第一个的数作为基准数。

  2. 将小于基准数的元素换到前面,将大于基准数的元素换到后面。

  3. 重复上述操作,直到区间只有一个数为止。

class Solution {
public:
    //快速排序
    void QuickSort(vector<int>& a,int l,int r)
    {
        if(l>=r) return;
        int i=l,j=r,temp=a[i];
        while(i<j)
        {
            while(i<j&&a[j]>=temp)
                j--;
            if(i<j)
            {
                a[i]=a[j];
                i++;
            }
            while(i<j&&a[i]<temp)
                i++;
            if(i<j)
            {
                a[j]=a[i];
                j--;
            }
        }
        a[i]=temp;
        QuickSort(a,l,i-1);
        QuickSort(a,i+1,r);
    }
    vector<int> MySort(vector<int>& arr) {
        QuickSort(arr,0,arr.size()-1);
        return arr;
    }
};
  • 堆排序

1、先将初始化的数组序列构建成大顶堆。

2、将堆顶元素和最后一个元素进行交换,此时最后一个元素的位置就是该序列的最大值了。然后再对其前面的所有元素进行堆更新,即从堆顶元素往下进行堆操作,但是这里已经排好序的最后一个元素不参与对操作。

3、重复上述步骤,每次都从堆顶取剩余元素的最大值放到堆即剩余元素的最后一个,然后从堆顶往下进行对操作,直至所有元素都已经操作完。

class Solution {
public:
    //堆排序
    void MaxHeapify(vector<int>& a,int start,int end)
    {
        int dad=start;
        int son=dad*2+1;
        while(son<=end)
        {
            if(son+1<=end&&a[son+1]>a[son])
                son++;
            if(a[dad]>a[son])
                return;
            else
            {
                swap(a[dad],a[son]);
                dad=son;
                son=dad*2+1;
            }
        }
    }
    void HeapSort(vector<int>& a)
    {
        for(int i=a.size()/2-1;i>=0;i--)
            MaxHeapify(a,i,a.size()-1);
        for(int i=a.size()-1;i>0;i--)
        {
            swap(a[0],a[i]);
            MaxHeapify(a,0,i-1);
        }
    }
    vector<int> MySort(vector<int>& arr) {
        HeapSort(arr);
        return arr;
    }
};
  • 二分查找法

1.确定搜索范围:初始化两个指针,left指向数组的起始位置,right指向数组的结束位置。

2.计算中间位置:计算中间位置的索引 mid,通常使用公式 mid = left + (right - left) / 2。

3.比较中间元素:比较数组中 mid 位置的元素与目标值 target。

如果 array[mid] 等于 target,则查找成功,返回 mid。

如果 array[mid] 小于 target,则目标值在 mid 的右侧,更新 left 为 mid + 1。

如果 array[mid] 大于 target,则目标值在 mid 的左侧,更新 right 为 mid - 1。

4.重复步骤:重复步骤2和3,直到 left 大于 right,此时搜索范围为空,表示目标值不存在于数组中。

5.返回结果:如果找到目标值,返回其索引;否则,返回一个表示未找到的特殊值(如 -1)。

// 二分查找模板函数
template <typename T>
int binarySearch(const T& container, const typename T::value_type& target) {
    int left = 0;
    int right = container.size() - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (container[mid] == target) {
            return mid; // 找到目标值,返回索引
        } else if (container[mid] < target) {
            left = mid + 1; // 目标值在右侧
        } else {
            right = mid - 1; // 目标值在左侧
        }
    }

    return -1; // 未找到目标值
}
  • 34
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值