自己模拟的栈可以开辟在堆上,它的空间可以是整个电脑的内存,相比于系统栈更大,减少了爆栈操作
代码演示:
#include
<iostream>
#include
<cstring>
#include
<stack>
using
namespace
std;
long
long
f(
long
long
n
) {
if
(
n
== 1)
return
1;
return
f(
n
- 1) *
n
;
}
typedef
struct
Data
{
//参数
int
n;
//状态码
int
code;
//记录返回值
long
long
ret, * pre_ret;
Data(
int
n
,
long
long
*
pre_ret
) : n(
n
), pre_ret(
pre_ret
) {
code = 0;
ret = 0;
}
}
Data
;
long
long
not_f(
long
long
n
) {
long
long
ans = 0;
Data
d(
n
, &ans);
stack
<
Data
> s;
s.push(d);
while
(!s.empty()) {
Data
&cur = s.top();
switch
(cur.code) {
//边界条件
case
0: {
if
(cur.n == 1) {
*cur.pre_ret = 1;
s.pop();
}
else
cur.code = 1;
}
break
;
//递推
case
1: {
Data
d(cur.n - 1, &cur.ret);
cur.code = 2;
s.push(d);
}
break
;
//递归
case
2: {
*cur.pre_ret = cur.ret * cur.n;
s.pop();
}
break
;
}
}
return
ans;
}
int
main() {
cout
<<
f(6)
<<
endl;
cout
<<
not_f(6)
<<
endl;
return
0;
}
quick_sort
void
quick_sort(
int
*
arr
,
int
l
,
int
r
) {
// code = 0
if
(
r
-
l
<= 2) {
if
(
r
-
l
<= 1)
return
;
if
(
arr
[
l
] >
arr
[
l
+ 1])
swap
(
arr
[
l
],
arr
[
l
+ 1]);
return
;
}
// code = 1, partition
int
x =
l
, y =
r
- 1, z =
arr
[
l
];
while
(x < y) {
while
(x < y && z <=
arr
[y]) --y;
if
(x < y)
arr
[x++] =
arr
[y];
while
(x < y &&
arr
[x] <= z) ++x;
if
(x < y)
arr
[y--] =
arr
[x];
}
arr
[x] = z;
// code = 2
quick_sort(
arr
,
l
, x);
// code = 3
quick_sort(
arr
, x + 1,
r
);
return
;
// code = 4
}
struct
Data
{
Data(
int
*
arr
,
int
l
,
int
r
)
: arr(
arr
), l(
l
), r(
r
), code(0) {}
int
*arr, l, r, x;
int
code;
};
void
non_quick_sort(
int
*
arr
,
int
l
,
int
r
) {
stack
<
Data
> s;
Data
d(
arr
,
l
,
r
);
s.push(d);
while
(!s.empty()) {
Data
&cur = s.top();
switch
(cur.code) {
case
0: {
if
(cur.r - cur.l <= 2) {
if
(cur.r - cur.l <= 1) s.pop();
else
{
if
(cur.arr[cur.l] > cur.arr[cur.l + 1]) {
swap
(cur.arr[cur.l], cur.arr[cur.l + 1]);
}
s.pop();
}
}
else
{
cur.code = 1;
}
}
break
;
case
1: {
int
x = cur.l, y = cur.r - 1, z = cur.arr[cur.l];
while
(x < y) {
while
(x < y && z <= cur.arr[y]) --y;
if
(x < y) cur.arr[x++] = cur.arr[y];
while
(x < y && cur.arr[x] <= z) ++x;
if
(x < y) cur.arr[y--] = cur.arr[x];
}
cur.arr[x] = z;
cur.x = x;
cur.code = 2;
}
break
;
case
2: {
Data
d(cur.arr, cur.l, cur.x);
cur.code = 3;
s.push(d);
}
break
;
case
3: {
Data
d(cur.arr, cur.x + 1, cur.r);
cur.code = 4;
s.push(d);
}
break
;
case
4: { s.pop(); }
break
;
}
}
return
;
}
拓扑序分解法
1.拓扑排序:
有向无环图:指的是一个无回路的有向图。如果有一个非有向无环图,且A点出发向B经C可回到A,形成一个环。将从C到A的边方向改为从A到C,则变成有向无环图。
一个有向无环图至少有一个入度为0的顶点和一个出度为0的顶点。
对一个
有向无环图
( Directed Acyclic Graph 简称 DAG ) G 进行拓扑排序,是将 G
中所有顶点排成一个线性序列,使得图中任意一对顶点 u 和 v ,若边 < u , v > ∈ E ( G ),则 u 在线性序列中出现在 v
之前。通常,这样的线性序列称为满足拓扑次序 ( Topological Order )
的序列,简称拓扑序列。
由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
ps:
-
离散数学中关于偏序和全序的定义:
若集合X上的关系是R,且R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
设R是集合X上的偏序(Partial Order),如果对每个x,y属于X必有xRy 或 yRx,则称R是集合X上的全序关系。
比较简单的理解:偏序是指集合中只有部分成员可以比较,全序是指集合中所有的成员之间均可以比较。
-
若图中存在有向环,则不可能使顶点满足拓扑次序。
2.作用:
图形的顶点可以表示要执行的任务(递归函数),并且边可以表示一个任务
(递归函数)
必须在另一个任务
(递归函数)
之前执行的约束;在这个应用中,拓扑排序只是一个有效的任务
(递归函数调用)
顺序,以此实现递归转非递归
拓扑排序实现过程:
1.找出入度为0的节点,入队
2.处理当前队首节点,将队首节点有向边指向的所有节点的入度减一,并将入度为一的节点入队(bfs)
3.队首元素出队,处理新的队首元素
4.循环至队为空
5.出队序列就为拓扑序列
代码演示:
#include
<iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<queue>
#include
<stack>
#include
<algorithm>
#include
<string>
#include
<map>
#include
<set>
#include
<vector>
using
namespace
std;
#define
MAX_N
2000
//入度
int
indeg[
MAX_N
+ 5] = {0};
//路径
vector
<
vector
<
int
>> g(
MAX_N
+ 5);
//拓扑序列
int
ans[
MAX_N
+ 5], cnt = 0;
int
main() {
int
n, m;
cin
>>
n
>>
m;
for
(
int
i = 0, a, b; i < m; i++) {
cin
>>
a
>>
b;
indeg[b] += 1;
g
[
a
]
.push_back(b);
}
set
<
int
> q;
for
(
int
i = 1; i <= n; i++) {
if
(indeg[i] == 0) q.insert(i);
}
while
(q.size() > 0) {
int
now =
*
q.begin();
// top()
ans[cnt++] = now;
q.erase(q.begin());
// pop()
//-------
for
(
int
i = 0, I = g
[
now
]
.size(); i < I; i++) {
int
t = g
[
now
][
i
]
;
indeg[t] -= 1;
if
(indeg[t] == 0) {
q.insert(t);
}
}
//-------
}
for
(
int
i = 0; i < n; i++) {
if
(i) cout
<<
" "
;
cout
<<
ans[i];
}
cout
<<
endl;
return
0;
}