leetcode刷题 十大排序算法 C++实现(剑指offer5个)

目录

0 综述

0.1算法分类

0.2 算法复杂度

0.3 相关概念

1 常考排序

1.1快速排序(Quick Sort)

1.2 归并排序(Merge Sort)

1.3 堆排序(Heap Sort)

2 普通排序算法

2.1冒泡排序

2.2选择排序(Selection Sort)

2.3 插入排序(Insertion Sort)

3 其他排序

3.1 希尔排序(Shell Sort)

3.2 基数排序(Radix Sort)

3.3 计数排序(Counting Sort)

3.4 桶排序(Bucket Sort)

4 排序思想应用题剑指offer

剑指 Offer 40. 最小的k个数  堆

剑指 Offer 41. 数据流中的中位数 最小堆 最大堆

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 快排

剑指 Offer 45. 把数组排成最小的数 拼接 快排

剑指 Offer 51. 数组中的逆序对 归并排序 

0 综述

0.1算法分类

十种常见排序算法可以分为两大类:

  • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 

0.2 算法复杂度

0.3 相关概念

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
  • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
  • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
  • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。 ‘

十大经典排序算法(动图演示)https://www.cnblogs.com/onepixel/p/7674659.html

1 常考排序

1.1快速排序(Quick Sort)

//快速排序
//双边循环法
int partion(int arr[],int low,int high)
{
	int startIndex=low;
	int pivot=arr[low];
	while(low=pivot)
		{
			high--;
		}
		while((low

1.2 归并排序(Merge Sort)

//归并排序
/*
使用分治思想:
假设两个子数组是有序的,将其按照有序序列合并,合并组成新的有序数组,再与其他部分合并
排序算法:归并排序【图解+代码】https://www.bilibili.com/video/BV1Pt4y197VZ?from=search&seid=7880178413492422518
*/
void merge(int arr[], int low, int mid, int high, int temp[])
{
    int i = low;         //左子数组开始位置
    int j = mid + 1;    //右子数组开始位置
    int t = 0;          //临时空间指针
    while (i <= mid && j <= high)
    {
        if (arr[i] < arr[j])
            temp[t++] = arr[i++];
        else
            temp[t++] = arr[j++];
    }
    //将左边剩余元素填充进temp中
    while (i <= mid)
        temp[t++] = arr[i++];
    //将右边子数组剩余部分填充到temp中
    while (j <= high)
        temp[t++] = arr[j++];
 
    //将融合后的数据拷贝到原来的数据对应的子空间中
    t = 0;
    while (low <= high)
    {
        arr[low++] = temp[t++];
    }
    
}
void MergeSort(int arr[], int low, int high, int temp[])
{
    if (low < high)             //只有low==high为一个元素的时候不用再细分自分组,融合
    {
        int mid = (low + high) / 2;
        //递归划分左半区
        MergeSort(arr, low, mid, temp);
        //递归划分右半区
        MergeSort(arr, mid + 1, high, temp);
        //合并已经排序的部分
        merge(arr, low, mid, high, temp);
    }
 
}

1.3 堆排序(Heap Sort)

//堆排序
#include
#include
using namespace std;
 
// 递归方式构建大根堆(len是arr的长度,index是第一个非叶子节点的下标)
void adjust(vector &arr, int len, int index)
{
    int left = 2*index + 1; // index的左子节点
    int right = 2*index + 2;// index的右子节点
 
    int maxIdx = index;
    if(left arr[maxIdx])     maxIdx = left;
    if(right arr[maxIdx])     maxIdx = right;
 
    if(maxIdx != index)
    {
        swap(arr[maxIdx], arr[index]);
        adjust(arr, len, maxIdx);
    }
 
}
 
// 堆排序
void heapSort(vector &arr, int size)
{
    // 构建大根堆(从最后一个非叶子节点向上)
    for(int i=size/2 - 1; i >= 0; i--)
    {
        adjust(arr, size, i);
    }
 
    // 调整大根堆
    for(int i = size - 1; i >= 1; i--)
    {
        swap(arr[0], arr[i]);           // 将当前最大的放置到数组末尾
        adjust(arr, i, 0);              // 将未完成排序的部分继续进行堆排序
    }
}
 
int main()
{
    vector arr = {8, 1, 14, 3, 21, 5, 7, 10};
    heapSort(arr, arr.size());
    for(int i=0;i

2 普通排序算法

2.1冒泡排序

//冒泡排序

//[0,1,2,3,4,5,6,7,8]
//len=9
//有8轮,i最大是7
void Bubble_Sort_v1(int* A,int len){
        for(int i=0;iA[j+1]){
                                int t = A[j+1];
                                A[j+1] = A[j];
                                A[j] = t;
                        }
                }
		}
}
void Bubble_Sort_v2(int* A,int len){
        for(int i=0;iA[j+1])
						{
                                int t = A[j+1];
                                A[j+1] = A[j];
                                A[j] = t;
								// 有元素交换,所以不是有序,标记变为false
								is_Sorted=false;
                        }
				
                }
			if (is_Sorted)
			{
				break;
			}
		}
}
void Bubble_Sort_v3(int* A,int len){
		// 记录最后一次交换的位置
		int last_exchange_index = 0;
		// 无序数列的边界,每次比较只需要比到这里为止
		int sort_border = len-1;
        for(int i=0;iA[j+1])
						{
                                int t = A[j+1];
                                A[j+1] = A[j];
                                A[j] = t;
								// 有元素交换,所以不是有序,标记变为false
								is_Sorted=false;
								// 把无序数列的边界更新为最后一次交换元素的位置
								last_exchange_index = j;
                        }
				
                        };
			sort_border = last_exchange_index;
			if (is_Sorted)
			{
				break;
			}
		}
}

2.2选择排序(Selection Sort)

//选择排序法
/*
从该位置后面选择最小的元素放在该位置
*/ 
 
void SelectSort(int a[],int len)
{
	//外层循环跑n趟
 
	for (int i = 0; i < len; i++){ 
		//内层循环找出最小值进行交换
		int tmp;
		for (int j = i; j < len; j++){ 
			if (a[j] < a[i]){
				tmp = a[j];
				a[j] = a[i];
				a[i] = tmp;
			}
		}
	}
}

2.3 插入排序(Insertion Sort)

// 插入排序法
 
/*
插入排序法:
拿着当前位置元素和前面的元素进行比较,只要当前元素比前面的元素大,则插入到该元素前面
直到前面的元素不满足要求,记录插入位置。
先拿出来 再比较插入
*/
 
void InsertSort(int a[], int len)
{
	int i, j, k; 
	int tmp;
	for (i = 1; i < len; i++)	{ 
		k = i;			//待插入元素位置
		tmp = a[k];	    //先拿出来
 
		for (j = i - 1; (j >= 0) && (a[j] > tmp); j--){
			a[j + 1] = a[j];			//只要大,则元素后移
			k = j;						//记录移动的位置
		} 
		a[k] = tmp;		//元素插入 
	} 
}

3 其他排序

3.1 希尔排序(Shell Sort)

3.2 基数排序(Radix Sort)

3.3 计数排序(Counting Sort)

3.4 桶排序(Bucket Sort)

4 排序思想应用题剑指offer

剑指 Offer 40. 最小的k个数  堆

https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/zi-jie-ti-ku-jian-40-jian-dan-zui-xiao-de-kge-shu-/

//堆思想
class Solution {
public:
    vector getLeastNumbers(vector& arr, int k) {
        if(arr.empty() || k == 0) {return {};}
        vector res(k);
        priority_queue max_heap;

        for(int i = 0; i < k; ++i) {max_heap.push(arr[i]);} // 用 arr 的前 k 个数填充最大堆
        for(int i = k; i < arr.size(); ++i) {
            if(arr[i] < max_heap.top()){
                max_heap.pop();
                max_heap.push(arr[i]); // 循环更新最大堆
            }
        }
        for(int i = 0; i < k; ++i) {
            res[i] = max_heap.top(); // 填充 res
            max_heap.pop();
        }

        return res;
    }
};

剑指 Offer 41. 数据流中的中位数 最小堆 最大堆

https://leetcode-cn.com/problems/find-median-from-data-stream/solution/zi-jie-ti-ku-295-kun-nan-shu-ju-liu-de-zhong-wei-s/

class MedianFinder {
public:
    /** initialize your data structure here. */
    priority_queue, less > maxheap;
    priority_queue, greater > minheap;

    MedianFinder() {

    }
    
    void addNum(int num) {
        if(maxheap.size() == minheap.size()) {
            maxheap.push(num);
            minheap.push(maxheap.top());
            maxheap.pop();
        }
        else {
            minheap.push(num);
            maxheap.push(minheap.top());
            minheap.pop();
        }
    }
    
    double findMedian() {
        return maxheap.size() == minheap.size() ? ((maxheap.top() + minheap.top()) * 0.5) : minheap.top();
    }
};

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 快排

//双边循环法
class Solution {
public:
    vector exchange(vector& nums) {

        int low = 0,high = nums.size() - 1;
        while(low
//单边循环法
class Solution {
public:
    vector exchange(vector& nums) {

        int low = 0,high = nums.size() - 1;
        int mark=low;
        for (int i=low;i<=high;i++)
        {
            if (nums[i]%2!=0)
            {	
                
                int tmp=nums[i];
                nums[i]=nums[mark];
                nums[mark]=tmp;
                mark++;
            }
        }
        return nums;
    }
};

剑指 Offer 45. 把数组排成最小的数 拼接 快排

C++ 先转换成字符串再组合https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/solution/c-xian-zhuan-huan-cheng-zi-fu-chuan-zai-zu-he-by-y/

//c++之to_string()函数 功能:将数值转化为字符串。返回对应的字符串。
class Solution {
public:
    string minNumber(vector& nums) {
        vectorstrs;
        string ans;
        for(int i = 0; i < nums.size(); i ++){
            strs.push_back(to_string(nums[i]));
        }
        sort(strs.begin(), strs.end(), [](string& s1, string& s2){return s1 + s2 < s2 + s1;});
        for(int i = 0; i < strs.size(); i ++)
            ans += strs[i];
        return ans;
    }
};

剑指 Offer 51. 数组中的逆序对 归并排序 

拓跋阿秀pdf

class Solution {
public:
    int reversePairs(vector& nums) {
        if( nums.size() <= 1) return 0;
        vector tmp(nums.size());
        return mergeSort(0, nums.size() - 1, nums, tmp);
    }
private:
    int mergeSort(int l, int r, vector& nums, vector& tmp) {
        // 终止条件
        if (l >= r) return 0;
        // 递归划分
        int m = l+(r-l)/2,res=0;
        // 合并阶段
        int i = l, j = m + 1, t = l;
        int leftRes = mergeSort(l, m, nums, tmp);
        int rightRes =  mergeSort(m+1, r, nums, tmp);
        while (i <= m && j <= r)
        {
            if (nums[i] <= nums[j])
                {
                    tmp[t++] = nums[i++];
                }
            else   
            {             
                res += (m - i + 1 );
                tmp[t++] = nums[j++];   
            }             
        }
        while(i<=m)
        {
            tmp[t++] = nums[i++];
        }
        while(j<=r)
        {
            tmp[t++] = nums[j++];
        }  
        //注意要有这一行              
        while (l <= r) {
				nums[l] = tmp[l];
				l++;
			}       
        return res + leftRes + rightRes;
    }
};    

 

你可能感兴趣的:(leetcode,刷题,C++,c++)