时间和空间复杂度<一>

谈到数据算法,就不得不提复杂度,书上解释很复杂这里不贴了,下面结合个人理解和代码做些简单记录,有的理解可能不准确或者错误。

时间复杂度

1.概念

执行程序所需要花费的时间,计算时可以简单认为就是执行最多语句的次数,注意:这里只是大致估算,若要真实时间需要另外编写测试程序

2.规则

a.只计算执行次数最多的代码

b.忽略不重要参数,只关心与数量变化很大时相关的表达式(变量级数,一般为n)

比如某段语句执行2n+3次,那么O(2n+3)=O(n),即时间复杂度为O(n)而不是O(2n+3)

c.复杂度与时间效率的关系:  
c < log2n < n < n*log2n < n^2 < n^3 < 2^n < 3^n < n! (c是一个常量,n!表示n^n)  
|--------------------------|--------------------------|-------------|  
          较好                     一般              较差 

3.例子

3.1-例1

a.执行次数

int i = 0, sum = 0, n = 100;	// 执行1次
for(i = 1; i < n; i++){		// 执行n+1次
	sum = sum + i;		// 执行n次
}

如上很容易看出,总共执行次数为1+(n+1)+n=2n+2

b.复杂度

忽略系数2和+2,所以O(2n+2)=O(n),即时间复杂度为O(n)

3-2-例2

printf("hello world\n);
printf("hello world\n);
printf("hello world\n);
printf("hello world\n);
printf("hello world\n);
printf("hello world\n);
a.执行次数

可以看出总共执行6次

b.复杂度

结合上面规则,是O(6),可是这样写对么?

不对,如果要表示执行固定多次,只能O(1),因此O(1)永然都表示执行次数是固定,哪怕是100次,也还是O(1)

空间复杂度

1.概念

执行程序所需要申请空间的大小,计算时可以简单认为就是操作/使用最多语句的次数,同样只是大致估算

2.规则

a.函数调用会申请空间一次,函数会使用和操作栈空间

b.手动分配内存会申请空间一次(比如malloc类函数),他们会操作堆空间

c.忽略不重要参数,只关心与数量变化很大时相关的表达式(变量级数,一般为n)

3.例子

3.1-例1

int *f(void){
	int *p = malloc(sizeof(int));
	return *p;
}
a.操作内存次数

调用函数操作一次栈,malloc操作一次堆,所以总共2次

b.复杂度

同上面一样,操作内存次数2为常量,所以O(2)=O(1)

3.2-例2

int *p[n], *q[n];
for(i = 0; i < n; i++){
	p[i] = malloc(sizeof(int));
	q[i] = malloc(sizeof(int));
}
a.操作内存次数
循环执行n次,循环里面分配两次空间,因此总共n*2=2n次

b.复杂度

同上可知O(2n)=O(n)


总结:

时间复杂度-判断执行次数最多语句,计算执行次数,取结果最高阶数

空间复杂度-判断分配/使用空间最多语句,计算执行次数,取结果最高阶数

#include <iostream> #include <fstream> #include <vector> #include <queue> #include <algorithm> using namespace std; class Graph { int V; vector<vector<int>>adj; vector<int>inDegree; public: Graph(int v):V(v),adj(v),inDegree(v,0){} voidaddEdge(int u,int v) { adj[u].push_back(v); inDegree[v]++; } void allTopologicalSortsUtil(vector<int>& res, vector<bool>& visited, vector<vector<int>>& allRes) { bool flag=false; for(int i =0;i<V;i++) { if(inDegree[i]==0&&!visited[i]) { for(int j:adj[i]) { inDegree[j]--; } res.push_back(i); visited[i]=true; allTopologicalSortsUtil(res,visited,allRes); visited[i]=false; res.pop_back(); for(int j:adj[i]) { inDegree[j]++; } flag=true; } } if(!flag){ if(res.size()==V) { allRes.push_back(res); } } } vector<vector<int>> allTopologicalSorts() { vector<int>res; vector<bool>visited(V, false); vector<vector<int>>allRes; allTopologicalSortsUtil(res,visited,allRes); return allRes; } }; Graph readGraphFromFile(const string& filename,int& numVertices) { ifstream file(filename); file >> numVertices; Graph g(numVertices); int u,v; while (file >>u>>v) { g.addEdge(u,v); } file.close(); return g; } void saveResultsToFile(const string& filename, const vector<vector<int>>& allRes) { ofstream file(filename); if(allRes.empty()) { file << 0<<" 个排列数"<<endl; } else { file<<allRes.size()<<" 个排列数"<<endl; for(const auto& res:allRes) { for(int vertex:res) { file << vertex << " "; } file << endl; } } file.close(); } int main() { string inputFilename="input.txt"; string outputFilename="output.txt"; int numVertices; Graph g=readGraphFromFile(inputFilename,numVertices); vector<vector<int>> allRes=g.allTopologicalSorts(); saveResultsToFile(outputFilename, allRes); return 0; } 分析算法时间复杂度空间复杂度
最新发布
12-30
拓扑排序算法是图论中的种基础且强大的算法,常用于解决有向无环图(DAG)中的节点排序问题。常见的实现方法有Kahn算法深度优先搜索(DFS)法。 ### 时间复杂度分析 - **Kahn算法**:Kahn算法时间复杂度为$O(V + E)$,其中$V$是节点数,$E$是边数。这是因为计算每个节点的入度需要遍历所有的边,耗时$O(E)$;进行广度优先搜索(BFS)时,每个节点每条边最多被访问次,共耗时$O(V + E)$,总的时间复杂度为$O(V + E)$[^2][^3]。 - **DFS法**:DFS法的时间复杂度同样为$O(V + E)$。DFS遍历需要访问每个节点每条边各次,因此时间复杂度也是$O(V + E)$[^3]。 ### 空间复杂度分析 - **Kahn算法**:Kahn算法需要使用个队列来存储入度为0的节点,以及个数组来记录每个节点的入度,其空间复杂度为$O(V)$。队列中最多存储$V$个节点,入度数组的大小也为$V$。 - **DFS法**:DFS法使用递归调用栈来实现深度优先搜索,递归栈的深度最大为$V$,因此空间复杂度为$O(V)$。此外,还需要个栈来存储拓扑排序的结果,栈的空间复杂度也为$O(V)$,总的空间复杂度为$O(V)$。 以下是Kahn算法DFS法的示例代码: ```cpp #include <iostream> #include <vector> #include <queue> #include <stack> using namespace std; // Kahn算法实现拓扑排序 vector<int> kahnTopologicalSort(const vector<vector<int>>& graph, int V) { vector<int> inDegree(V, 0); for (const auto& neighbors : graph) { for (int neighbor : neighbors) { inDegree[neighbor]++; } } queue<int> q; for (int i = 0; i < V; ++i) { if (inDegree[i] == 0) { q.push(i); } } vector<int> topoOrder; while (!q.empty()) { int u = q.front(); q.pop(); topoOrder.push_back(u); for (int v : graph[u]) { if (--inDegree[v] == 0) { q.push(v); } } } return topoOrder; } // DFS法实现拓扑排序 void dfs(const vector<vector<int>>& graph, int u, vector<bool>& visited, stack<int>& topoOrder) { visited[u] = true; for (int v : graph[u]) { if (!visited[v]) { dfs(graph, v, visited, topoOrder); } } topoOrder.push(u); } vector<int> dfsTopologicalSort(const vector<vector<int>>& graph, int V) { vector<bool> visited(V, false); stack<int> topoOrder; for (int i = 0; i < V; ++i) { if (!visited[i]) { dfs(graph, i, visited, topoOrder); } } vector<int> result; while (!topoOrder.empty()) { result.push_back(topoOrder.top()); topoOrder.pop(); } return result; } int main() { int V = 6; vector<vector<int>> graph = {{1, 2}, {3}, {3, 4}, {5}, {5}, {}}; vector<int> kahnResult = kahnTopologicalSort(graph, V); vector<int> dfsResult = dfsTopologicalSort(graph, V); cout << "Kahn算法拓扑排序结果: "; for (int node : kahnResult) { cout << node << " "; } cout << endl; cout << "DFS法拓扑排序结果: "; for (int node : dfsResult) { cout << node << " "; } cout << endl; return 0; } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值