算法笔记本

算法笔记本

基础算法

得背下来

[收藏的网站]([内排序]八大经典排序合集 - C3Stones - 博客园 (cnblogs.com))

快排

分治思想

不同于常规的,不是一次排序一个数,而是直接将某个数的俩测排好

1258817-20190325195811497-310078615

5b56d02d73d145ca9be2c0431f1f6d68_tplv-k3u1fbpfcp-watermark (1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<iostream>

using namespace std;

const int N = 1e6 + 10;

int n;
int q[N];

void quick_sort(int q[],int left,int right)
{
if(left>=right) return ;
int x=q[(left+right+1)/2],i=left-1,j=right+1;//可换成x=q[(left+right)/2]
while(i<j)
{
do i++ ;while(q[i]<x);
do j-- ;while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}

quick_sort(q,left,i-1);//可换成j
quick_sort(q,i,right);//可换成j-1

}

int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&q[i]);

quick_sort(q,0,n-1);

for(int i=0;i<n;i++)
printf("%d ",q[i]);

return 0;
}

归并排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<iostream>

using namespace std;

const int N=1000010;

int n;
int q[N],temp[N];


void merge_sort(int q[],int left,int right)
{
if(left>=right) return ;
@WWWWWWWW*x
int mid=(left+right)/2;[p;'p-=l.;;;;76']

merge_sort(q,left,mid), merge_sort(q,mid+1,right);

int x=0,i=left,j=mid+1;

while(i<=mid&&j<=right)//注意这里的 <=
if(q[i]<=q[j]) temp[x++]=q[i++];//注意这里的 <=
else temp[x++]=q[j++];
while(i<=mid) temp[x++]=q[i++];//注意这里的 <=
while(j<=right) temp[x++]=q[j++];//注意这里的 <=

for(i=left,j=0;i<=right;i++,j++)//注意这里的 <=
q[i]=temp[j];

}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&q[i]);

merge_sort(q,0,n-1);

for(int i=0;i<n;i++)
printf("%d ",q[i]);
}

二分

时间复杂度

一般ACM或者笔试题的时间限制是1秒或2秒。
在这种情况下,C++代码中的操作次数控制在 107∼108107∼108 为最佳。

下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:

  • n≤30n≤30, 指数级别, dfs+剪枝,状态压缩dp
  • n≤100n≤100 => O(n3)O(n3),floyd,dp,高斯消元
  • n≤1000n≤1000 => O(n2)O(n2),O(n2logn)O(n2logn),dp,二分,朴素版Dijkstra、朴素版Prim、Bellman-Ford
  • n≤10000n≤10000 => O(n∗n√)O(n∗n),块状链表、分块、莫队
  • n≤100000n≤100000 => O(nlogn)O(nlogn) => 各种sort,线段树、树状数组、set/map、heap、拓扑排序、dijkstra+heap、prim+heap、Kruskal、spfa、求凸包、求半平面交、二分、CDQ分治、整体二分、后缀数组、树链剖分、动态树
  • n≤1000000n≤1000000 => O(n)O(n), 以及常数较小的 O(nlogn)O(nlogn) 算法 => 单调队列、 hash、双指针扫描、并查集,kmp、AC自动机,常数比较小的 O(nlogn)O(nlogn) 的做法:sort、树状数组、heap、dijkstra、spfa
  • n≤10000000n≤10000000 => O(n)O(n),双指针扫描、kmp、AC自动机、线性筛素数
  • n≤109n≤109 => O(n√)O(n),判断质数
  • n≤1018n≤1018 => O(logn)O(logn),最大公约数,快速幂,数位DP
  • n≤101000n≤101000 => O((logn)2)O((logn)2),高精度加减乘除
  • n≤10100000n≤10100000 => O(logk×loglogk),k表示位数O(logk×loglogk),k表示位数,高精度加减、FFT/NTT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
1插入排序

void insert_sort()
{
for (int i = 1; i < n; i ++ )
{
int x = a[i];
int j = i-1;

while (j >= 0 && x < a[j])
{
a[j+1] = a[j];
j -- ;
}
a[j+1] = x;
}
}
2选择排序

void select_sort()
{
for (int i = 0; i < n; i ++ )
{
int k = i;
for (int j = i+1; j < n; j ++ )
{
if (a[j] < a[k])
k = j;
}
swap(a[i], a[k]);
}

}
3冒泡排序

void bubble_sort()
{
for (int i = n-1; i >= 1; i -- )
{
bool flag = true;
for (int j = 1; j <= i; j ++ )
if (a[j-1] > a[j])
{
swap(a[j-1], a[j]);
flag = false;
}
if (flag) return;
}
}
4希尔排序

void shell_sort()
{
for (int gap = n >> 1; gap; gap >>= 1)
{
for (int i = gap; i < n; i ++ )
{
int x = a[i];
int j;
for (j = i; j >= gap && a[j-gap] > x; j -= gap)
a[j] = a[j-gap];
a[j] = x;
}
}
}
5快速排序(最快)

void quick_sort(int l, int r)
{
if (l >= r) return ;

int x = a[l+r>>1], i = l-1, j = r+1;
while (i < j)
{
while (a[++ i] < x);
while (a[-- j] > x);
if (i < j) swap(a[i], a[j]);
}
sort(l, j), sort(j+1, r);
}
6归并排序

void merge_sort(int l, int r)
{
if (l >= r) return;
int temp[N];
int mid = l+r>>1;
merge_sort(l, mid), merge_sort(mid+1, r);
int k = 0, i = l, j = mid+1;
while (i <= mid && j <= r)
{
if (a[i] < a[j]) temp[k ++ ] = a[i ++ ];
else temp[k ++ ] = a[j ++ ];

}
while (i <= mid) temp[k ++ ] = a[i ++ ];
while (j <= r) temp[k ++ ] = a[j ++ ];
for (int i = l, j = 0; i <= r; i ++ , j ++ ) a[i] = temp[j];
}
7堆排序(须知此排序为使用了模拟堆,为了使最后一个非叶子节点的编号为n/2,数组编号从1开始)
https://www.cnblogs.com/wanglei5205/p/8733524.html

void down(int u)
{
int t = u;
if (u<<1 <= n && h[u<<1] < h[t]) t = u<<1;
if ((u<<1|1) <= n && h[u<<1|1] < h[t]) t = u<<1|1;
if (u != t)
{
swap(h[u], h[t]);
down(t);
}
}

int main()
{
for (int i = 1; i <= n; i ++ ) cin >> h[i];
for (int i = n/2; i; i -- ) down(i);
while (true)
{
if (!n) break;
cout << h[1] << ' ';
h[1] = h[n];
n -- ;
down(1);
}
return 0;
}
8基数排序

int maxbit()
{
int maxv = a[0];
for (int i = 1; i < n; i ++ )
if (maxv < a[i])
maxv = a[i];
int cnt = 1;
while (maxv >= 10) maxv /= 10, cnt ++ ;

return cnt;
}
void radixsort()
{
int t = maxbit();
int radix = 1;

for (int i = 1; i <= t; i ++ )
{
for (int j = 0; j < 10; j ++ ) count[j] = 0;
for (int j = 0; j < n; j ++ )
{
int k = (a[j] / radix) % 10;
count[k] ++ ;
}
for (int j = 1; j < 10; j ++ ) count[j] += count[j-1];
for (int j = n-1; j >= 0; j -- )
{
int k = (a[j] / radix) % 10;
temp[count[k]-1] = a[j];
count[k] -- ;
}
for (int j = 0; j < n; j ++ ) a[j] = temp[j];
radix *= 10;
}

}
9计数排序

void counting_sort()
{
int sorted[N];
int maxv = a[0];
for (int i = 1; i < n; i ++ )
if (maxv < a[i])
maxv = a[i];
int count[maxv+1];
for (int i = 0; i < n; i ++ ) count[a[i]] ++ ;
for (int i = 1; i <= maxv; i ++ ) count[i] += count[i-1];
for (int i = n-1; i >= 0; i -- )
{
sorted[count[a[i]]-1] = a[i];
count[a[i]] -- ;
}
for (int i = 0; i < n; i ++ ) a[i] = sorted[i];
}
10桶排序(基数排序是桶排序的特例,优势是可以处理浮点数和负数,劣势是还要配合别的排序函数)

vector<int> bucketSort(vector<int>& nums) {
int n = nums.size();
int maxv = *max_element(nums.begin(), nums.end());
int minv = *min_element(nums.begin(), nums.end());
int bs = 1000;
int m = (maxv-minv)/bs+1;
vector<vector<int> > bucket(m);
for (int i = 0; i < n; ++i) {
bucket[(nums[i]-minv)/bs].push_back(nums[i]);
}
int idx = 0;
for (int i = 0; i < m; ++i) {
int sz = bucket[i].size();
bucket[i] = quickSort(bucket[i]);
for (int j = 0; j < sz; ++j) {
nums[idx++] = bucket[i][j];
}
}
return nums;
}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!