算法第四版- 2.1,2.2

算法第四版- 2.1,2.2

排序基础篇

1.希尔排序

课本上的希尔排序

void ShellSort(vector<int> a)
{
	int N = a.size();
	int h = 1;
	while (h < N / 3) h = 3 * h + 1;
	while (h >= 1)
	{
		//将数组变成h有序
		for (int i = h; i < N; i++)
		{
			//将a[i]插入到a[i-h],a[i-2*h],a[i-3*h]
			for (int j = i; j >= h && a[j] < a[j - h]; j -= h)
			{
				swap(a[j], a[j - h]);
			}
			h = h / 3;
		}
	}

}

关于如何理解这段代码:
希尔排序-小灰的漫画算法

2.归并排序

这次不用书上的代码,用的左程云网课的代码

class Code01_MergeSort
{
public:
	void mergeSort(int *arr, int size)
	{
		if (arr == nullptr || size < 2)
			return;
		process(arr, 0, size - 1);
	}
	void merge(int* arr, int L, int M, int R)
	{
		int* help = new int[R - L + 1];
		int i = 0;
		int p1 = L;
		int p2 = M + 1;
		while (p1 <= M && p2 <= R)
		{
			help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
		}
		while (p1 <= M)
			help[i++] = arr[p1++];
		while (p2 <= R)
			help[i++] = arr[p2++];
		for (int i = 0; i < R - L + 1; i++)
			arr[L + i] = help[i];
		delete[]help;
	}
	void process(int* arr, int L, int R)
	{
		if (L == R) return;
		int mid = L + (R - L) >> 2;
		process(arr, L, mid);
		process(arr, mid + 1, R);
		merge(arr, L, mid, R);
	}
};

关于如何理解这段代码-小灰的漫画算法-归并排序

杂记

1)选择排序+插入排序

选择排序-漫画
插入排序-漫画

2)基数排序

基数排序-漫画
然后,放一下左神的代码

#include <iostream>
#include <vector>
using namespace std;
void radixSort(int* arr,int size)
{
	if (arr == nullptr || size < 2)
		return;
	radixSort(arr, 0, size - 1, maxbits(arr, size));
}
int maxbits(int* arr,int size)
{
	int max1 = 0;
	for (int i = 0; i < size; i++)
		max1 = max(max1, arr[i]);
	int res = 0;
	while (max1 != 0)
	{

		res++;
		max1 /= 10;
	}
	return res;
		//最大值的位数
}
int getDigit(int x, int d)
{
	return ((x / ((int)pow(10, d - 1))) % 10);
}
void radixSort(int* arr, int L, int R, int digit)
{
	const int radix = 10;
	int i = 0, j = 0;
	vector<int> bucket(R - L + 1);
	for (int d = 1; d <= digit; d++)//有多少位就进出多少次
	{  
		//10个空间
		//count[i], 当前位(d位)是(0~i)的数字有多少个
		vector<int> count(radix);
		for (i = L; i <= R; i++)
		{
			j = getDigit(arr[i], d);  //把arr[i]在d位的数字取出来
			count[j]++;
		}
		for (i = 1; i < radix; i++)
		{
			count[i] = count[i] + count[i - 1];
		}
		for (i = R; i >= L; i--)
		{
			j = getDigit(arr[i], d);
			bucket[count[j] - 1] = arr[i];
			count[j]--;
		}
		for (i = L, j = 0; i <= R; i++, j++)
		{
			arr[i] = bucket[j];
		}
	}
}

3)多变量排序方法

在做算法4习题2.1.21的时候,发现了并不是只有简单的一维的排序,还可能有多种状态。
在这举一些compare如何写,以及lambda表达式的写法。
我们来看一下LC第1337题
1337.矩阵中战斗力最弱的几行
sort的第三个参数
二维数组直接排序,这个方便的程度超出我想象了。
vector可以直接排序,本质是一个指针,排序方法从第一个元素到最后一个元素依次比较,不相等返回结果{1,1,0}>{1,0,0}
1.首先是lambda表达式版本的

class Solution {
public:
    vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
        int n=mat.size();
        int m=mat[0].size();
        vector<int> ans;
        for(int i=0;i<n;i++) ans.push_back(i);
        sort(ans.begin(),ans.end(),[&](const int& a,const int & b){return mat[a]==mat[b]?a<b:mat[a]<mat[b];});
        vector<int> r(ans.begin(),ans.begin()+k);
        return r;

    }
};

2.其实我想要的是类似于哈希表,有first,second这种版本的
注意一下pair的使用

class Solution {
public:
    vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {        
        int n = mat.size();
        vector<pair<int, int>> power;
        for (int i = 0; i < n; ++i) {
            int sum = accumulate(mat[i].begin(), mat[i].end(), 0);
            power.emplace_back(sum, i);
        }
        sort(power.begin(), power.end());
        vector<int> ans;
        for (int i = 0; i < k; ++i) {
            ans.push_back(power[i].second);
        }
        return ans;
     }
};        

3.其实我想要再补充一下的是结构体类型的cmp函数咋写,类似于下面这样吧,还补充了一下严格弱序:
严格弱序

4)插入排序的哨兵

哨兵最早是在王道视频里看到的。所以这次的代码参考咸鱼学长的

普通的插入排序如下:

void InsertSort(int A[], int n)
{
	int i, j, temp;
	for (i = 1; i < n; i++)
	{
		if (A[i] < A[i - 1])
		{
			temp = A[i];
			for (j = i - 1; j >= 0 && A[j] > temp; --j)
				A[j + 1] = A[j];
			A[j + 1] = temp;
		}
	}
}

带哨兵的如下:
xjy
哨兵的好处就是不用再判断j>=0了
因为当j=0的时候,A[0]<A[j]不满足,自动就跳出了for循环。

备注:
例题2.2.11是对归并排序的改进,但是懒得再去看java代码了。
对于排序这边没什么兴趣,毕竟可以直接调sort函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值