一个C#和C++执行效率对比的简单实例

这里用一个算法题进行比较。

原题是见http://acm.hdu.edu.cn/showproblem.php?pid=4090,登载在http://blog.csdn.net/woshi250hua/article/details/7997550

作者提供了一个比较快的答案。

我之前也尝试做了一个,没有用递归,但也没有用作者使用的格局保存的剪枝方案,比较慢,随后看了作者的方案后再整合进了一个基本等效的格局保存逻辑。

以下是作者的C++程序的基本等价的C#程序,

  1 using System.Collections.Generic;

  2 

  3 namespace HDU4090

  4 {

  5     internal class SolveGemAndPrince2

  6     {

  7         private const int Max = 10;

  8 

  9         private struct Node

 10         {

 11             public int X;

 12             public int Y;

 13         }

 14 

 15         private readonly Node[] _qu = new Node[Max*Max];

 16         private readonly Dictionary<string, int> _hash = new Dictionary<string, int>();

 17 

 18         private readonly int[,] _dir = new[,]

 19             {

 20                 {1, 0}, {1, 1}, {1, -1}, {-1, 0}, {-1, -1}, {-1, 1}, {0, 1}, {0, -1}

 21             };

 22 

 23         private static void Change(int[,] mmap, ref int n, ref int m)

 24         {

 25             int i, j, tn = 0, tm = 0;

 26             var k = new int[10];

 27             for (j = 0; j < m; ++j)

 28             {

 29 

 30                 k[j] = 0;

 31                 for (i = 0; i < n; ++i)

 32                     if (mmap[i, j] != 0) mmap[k[j]++, j] = mmap[i, j];

 33             }

 34             for (j = 0; j < m; ++j)

 35                 if (k[j] != 0)

 36                 {

 37 

 38                     for (i = 0; i < k[j]; ++i)

 39                         mmap[i, tm] = mmap[i, j];

 40                     for (i = k[j]; i < n; ++i)

 41                         mmap[i, tm] = 0;

 42                     tm++;

 43                     if (k[j] > tn) tn = k[j];

 44                 }

 45             n = tn;

 46             m = tm;

 47         }

 48 

 49         private int Ok(int[,] temp, int[,] vis, int i, int j, int n, int m)

 50         {

 51             var cnt = 0;

 52             int head = 0, tail = 0;

 53             Node cur;

 54 

 55             cur.X = i;

 56             cur.Y = j;

 57             _qu[head++] = cur;

 58             vis[cur.X,cur.Y] = 1;

 59 

 60             while (tail < head)

 61             {

 62                 cur = _qu[tail++];

 63                 cnt++;

 64                 int k;

 65                 for (k = 0; k < 8; ++k)

 66                 {

 67                     Node next;

 68                     next.X = cur.X + _dir[k,0];

 69                     next.Y = cur.Y + _dir[k,1];

 70                     if (next.X >= 0 && next.X < n

 71                         && next.Y >= 0 && next.Y < m

 72                         && vis[next.X,next.Y] == 0

 73                         && temp[next.X,next.Y] == temp[i,j])

 74                     {

 75 

 76                         _qu[head++] = next;

 77                         vis[next.X,next.Y] = 1;

 78                         temp[next.X,next.Y] = 0;

 79                     }

 80                 }

 81             }

 82             temp[i,j] = 0;

 83             return cnt >= 3 ? cnt : 0;

 84         }

 85 

 86         static string GetHash(int[,] temp,int n,int m)

 87         {

 88             var s = "";

 89             for (var i = 0; i < n; ++i)

 90                 for (var j = 0; j < m; ++j)

 91                     s += temp[i,j] + '0';

 92             return s;

 93         }

 94 

 95         static void Mem(int[,] temp, int[,] mmap, int n, int m)

 96         {

 97             for (var i = 0; i < Max; i++ )

 98                 for (var j = 0; j < Max; j++)

 99                     temp[i, j] = 0;

100             for (var i = 0; i < n; ++i)

101                 for (var j = 0; j < m; ++j)

102                     temp[i,j] = mmap[i,j];

103         }

104 

105         int Dfs(int[,] mmap,int n,int m)

106         {

107 

108             if (n*m < 3) return 0;

109             var temp = new int[Max,Max];

110             int i, j;

111             var vis = new int[Max,Max];

112             var cnt = 0;

113 

114             for (i = 0; i < n; ++i)

115                 for (j = 0; j < m; ++j)

116                     if (vis[i,j]==0 && mmap[i,j]!=0)

117                     {

118                         Mem(temp, mmap, n, m);

119                         var ans = Ok(temp, vis, i, j, n, m);

120                         if (ans >= 3)

121                         {

122                             ans = ans*ans;

123                             int tn = n, tm = m;

124                             Change(temp, ref tn, ref tm);

125                             var s = GetHash(temp, tn, tm);

126 #if true

127                             if (!_hash.ContainsKey(s))

128                                 ans += Dfs(temp, tn, tm);

129                             else ans += _hash[s];

130 #else

131                             ans += Dfs(temp, tn, tm);

132 #endif

133                             if (ans > cnt) cnt = ans;

134                         }

135                     }

136 

137             _hash[GetHash(mmap, n, m)] = cnt;

138             return cnt;

139         }

140 

141         public int Solve(int n, int m, int k, int[,] gems)

142         {

143             _hash.Clear();

144             return Dfs(gems, n, m);

145         }

146     }

147 }

再接下来是我的方案(纯粹凑热闹,没有参与这里的对比),

  1 using System;

  2 using System.Collections.Generic;

  3 

  4 namespace HDU4090

  5 {

  6     public class SolveGemAndPrince

  7     {

  8         #region Nested types

  9 

 10         class Node

 11         {

 12             #region Nested types

 13 

 14             public class Gem

 15             {

 16                 public int Row { get; set; }

 17                 public int Col { get; set; }

 18             }

 19 

 20             public class Connective

 21             {

 22                 public readonly List<Gem> Connected = new List<Gem>();

 23             }

 24 

 25             #endregion

 26 

 27             #region Properties

 28 

 29             private int[,] Gems { get; set; }

 30             public List<Connective> Connectives { get; private set; }

 31             public int Try { get; set; }

 32             public int Score { get; private set; }

 33 

 34             #endregion

 35 

 36             #region Constructors

 37 

 38             public Node(int rows, int cols, int[,] gems, int iniScore)

 39             {

 40                 _rows = rows;

 41                 _cols = cols;

 42                 Score = iniScore;

 43                 Connectives = new List<Connective>();

 44                 Gems = gems;

 45                 Segment();

 46             }

 47 

 48             #endregion

 49 

 50             #region Methods

 51 

 52             public string GetHash()

 53             {

 54                 var hash = "";

 55                 foreach (var gem in Gems)

 56                 {

 57                     hash += gem.ToString() + '0';

 58                 }

 59                 return hash;

 60             }

 61 

 62             void AddToConnective(Connective connective, bool[,] visited, int r, int c)

 63             {

 64                 visited[r, c] = true;

 65                 connective.Connected.Add(new Gem { Row = r, Col = c });

 66                 var imin = Math.Max(0, r - 1);

 67                 var imax = Math.Min(_rows - 1, r + 1);

 68                 var jmin = Math.Max(0, c - 1);

 69                 var jmax = Math.Min(_cols - 1, c + 1);

 70                 var cur = Gems[r, c];

 71                 for (var i = imin; i <= imax; i++)

 72                 {

 73                     for (var j = jmin; j <= jmax; j++)

 74                     {

 75                         if (visited[i, j]) continue;

 76                         var val = Gems[i, j];

 77                         if (val == cur)

 78                         {   // TODO recursive, improve it

 79                             AddToConnective(connective, visited, i, j);

 80                         }

 81                     }

 82                 }

 83             }

 84 

 85             void Segment()

 86             {

 87                 var visited = new bool[_rows, _cols];

 88                 for (var i = 0; i < _rows; i++)

 89                 {

 90                     for (var j = 0; j < _cols; j++)

 91                     {

 92                         if (visited[i, j] || Gems[i, j] == 0) continue;

 93                         var connective = new Connective();

 94                         AddToConnective(connective, visited, i, j);

 95                         if (connective.Connected.Count < 3) continue;

 96                         Connectives.Add(connective);

 97                     }

 98                 }

 99             }

100 

101             public Node Action(int path)

102             {

103                 var connective = Connectives[path];

104                 var gems = Copy();

105                 var firstNonZeroRow = _rows;

106                 var firstNonZeroCol = 0;

107 

108                 foreach (var gem in connective.Connected)

109                 {

110                     gems[gem.Row, gem.Col] = 0;

111                 }

112                 // processes falling

113                 var newcols = 0;

114                 for (var i = 0; i < _cols; i++)

115                 {

116                     var k = _rows - 1;

117                     for (var j = _rows - 1; j >= 0; j--)

118                     {

119                         if (gems[j, i] > 0)

120                         {

121                             gems[k--, i] = gems[j, i];

122                         }

123                     }

124                     for (var t = 0; t <= k; t++)

125                     {

126                         gems[t, i] = 0;

127                     }

128                     if (k + 1 < firstNonZeroRow) firstNonZeroRow = k + 1;

129                     if (k + 1 < _rows)

130                     {   // non-empty

131                         newcols++;

132                     }

133                     else if (i == firstNonZeroCol)

134                     {

135                         firstNonZeroCol = i;

136                     }

137                 }

138                 // processes shifting

139 

140                 var newrows = _rows - firstNonZeroRow;

141                 var newgems = new int[newrows, newcols];

142                 var tcol = 0;

143                 for (var j = firstNonZeroCol; j < _cols; j++)

144                 {

145                     if (gems[_rows - 1, j] == 0) continue;  // empty column

146                     for (var i = firstNonZeroRow; i < _rows; i++)

147                     {

148                         newgems[i - firstNonZeroRow, tcol] = gems[i, j];

149                     }

150                     tcol++;

151                 }

152                 var count = connective.Connected.Count;

153                 var scoreInc = count*count;

154                 return new Node(newrows, newcols, newgems, Score + scoreInc);

155             }

156 

157             int[,] Copy()

158             {

159                 var gems = new int[_rows,_cols];

160                 for (var i = 0; i < _rows; i++)

161                 {

162                     for (var j =0; j < _cols; j++)

163                     {

164                         gems[i, j] = Gems[i, j];

165                     }

166                 }

167                 return gems;

168             }

169 

170             #endregion

171 

172             #region Fields

173 

174             private readonly int _rows;

175             private readonly int _cols;

176 

177             #endregion

178         }

179 

180         #endregion

181 

182         #region Methods

183 

184         /// <summary>

185         ///  Solves the gem-and-prince problem presented in HDU-4090

186         ///  http://acm.hdu.edu.cn/showproblem.php?pid=4090

187         ///  found from the post at

188         ///  http://blog.csdn.net/woshi250hua/article/details/7997550

189         /// </summary>

190         /// <param name="n">The number of rows the gem grid contains; might well be ignored in C#</param>

191         /// <param name="m">The number of columns the gem grid contains; might well be ignored in C#</param>

192         /// <param name="k">The inclusive upper bound of gem values of which the minimum is always 0 which means there is no gem</param>

193         /// <param name="gems">The initial grid of gems</param>

194         /// <returns>The highest score that can be achieved by the solution</returns>

195         public int Solve(int n, int m, int k, int[,] gems)

196         {

197             _records.Clear();

198             var root = new Node(n, m, gems, 0);

199             var stack = new Stack<Node>();

200             var highest = 0;

201             stack.Push(root);

202 

203             while (stack.Count > 0)

204             {

205                 var node = stack.Pop();

206 

207 

208                 if (node.Try >= node.Connectives.Count) continue;

209                 var newNode = node.Action(node.Try);

210                 node.Try++;

211                 stack.Push(node);

212 

213 #if true    // optimisation

214                 var hash = newNode.GetHash();

215                 if (_records.ContainsKey(hash))

216                 {

217                     var oldScore = _records[hash];

218                     if (newNode.Score <= oldScore)

219                         continue;

220                 }

221 

222                 _records[hash] = newNode.Score;

223 #endif

224                 

225                 if (newNode.Score > highest)

226                 {

227                     highest = newNode.Score;

228                 }

229                 stack.Push(newNode);

230             }

231             return highest;

232         }

233 

234         #endregion

235 

236         #region Fields

237 

238         readonly Dictionary<string,int> _records = new Dictionary<string, int>(); 

239 

240         #endregion

241     }

242 }

测试程序和样本:

 

  1 using System;

  2 

  3 namespace HDU4090

  4 {

  5     class Program

  6     {

  7         struct Sample

  8         {

  9             public int N, M, K;

 10             public int[,] Data;

 11         }

 12 

 13         private static Sample[] Samples = new Sample[]

 14             {

 15                 new Sample

 16                     {

 17                         N = 5,

 18                         M = 5,

 19                         K = 5,

 20                         Data =

 21                             new[,]

 22                                 {

 23                                     {1, 2, 3, 4, 5},

 24                                     {1, 2, 2, 2, 1},

 25                                     {1, 2, 1, 2, 1},

 26                                     {1, 2, 2, 2, 2},

 27                                     {1, 2, 3, 3, 5}

 28                                 }

 29                     },

 30                 new Sample

 31                     {

 32                         N = 3,

 33                         M = 3,

 34                         K = 3,

 35                         Data =

 36                             new[,]

 37                                 {

 38                                     {1, 1, 1},

 39                                     {1, 1, 1},

 40                                     {2, 3, 3}

 41                                 }

 42                     },

 43                 new Sample

 44                     {

 45                         N = 4,

 46                         M = 4,

 47                         K = 3,

 48                         Data =

 49                             new[,]

 50                                 {

 51                                     {1, 1, 1, 3},

 52                                     {2, 1, 2, 3},

 53                                     {1, 2, 1, 3},

 54                                     {3, 3, 3, 3}

 55                                 }

 56                     },

 57                 new Sample

 58                     {

 59                         N = 4,

 60                         M = 4,

 61                         K = 2,

 62                         Data =

 63                             new[,]

 64                                 {

 65                                     {1, 2, 1, 2},

 66                                     {2, 1, 2, 1},

 67                                     {1, 2, 1, 2},

 68                                     {2, 1, 2, 1}

 69                                 }

 70                     },

 71                 new Sample

 72                     {

 73                         N = 8,

 74                         M = 8,

 75                         K = 6,

 76                         Data =

 77                             new[,]

 78                                 {

 79                                     {1, 1, 1, 1, 1, 1, 1, 1},

 80                                     {2, 2, 2, 2, 2, 2, 2, 2},

 81                                     {3, 3, 3, 3, 3, 3, 3, 3},

 82                                     {4, 4, 4, 4, 4, 4, 4, 4},

 83                                     {5, 5, 5, 5, 5, 5, 5, 5},

 84                                     {6, 6, 6, 6, 6, 6, 6, 6},

 85                                     {6, 6, 6, 6, 6, 6, 6, 6},

 86                                     {6, 6, 6, 6, 6, 6, 6, 6}

 87                                 }

 88                     },

 89                 new Sample

 90                     {

 91                         N = 8,

 92                         M = 8,

 93                         K = 6,

 94                         Data =

 95                             new[,]

 96                                 {

 97                                     {6, 6, 6, 6, 6, 6, 6, 6},

 98                                     {6, 6, 6, 6, 6, 6, 6, 6},

 99                                     {6, 6, 6, 6, 6, 6, 6, 6},

100                                     {6, 6, 6, 6, 6, 6, 6, 6},

101                                     {6, 6, 6, 6, 6, 6, 6, 6},

102                                     {6, 6, 6, 6, 6, 6, 6, 6},

103                                     {6, 6, 6, 6, 6, 6, 6, 6},

104                                     {6, 6, 6, 6, 6, 6, 6, 6}

105                                 }

106                     },

107             };

108 

109 

110         private static int[] _key = {166,36,94,128,896,4096};

111 

112         static void Main(string[] args)

113         {

114             var solve = new SolveGemAndPrince();

115             var solve2 = new SolveGemAndPrince2();

116             var time1 = DateTime.Now;

117             for (var i = 0; i < 10000; i++ )

118             {

119                 int t = 0;

120                 foreach (var sample in Samples)

121                 {

122                     var result = solve.Solve(sample.N, sample.M, sample.K, sample.Data);

123                     //var result = solve2.Solve(sample.N, sample.M, sample.K, sample.Data);

124                     //Console.WriteLine("Highest score achievable = {0}", result);

125                     if (result != _key[t++])

126                     {

127                         Console.WriteLine("error!");

128                         return;

129                     }

130                 }

131             }

132             var time2 = DateTime.Now;

133             var span = time2 - time1;

134             Console.WriteLine("Done {0}", span.TotalSeconds);

135         }

136     }

137 }

将工程编译都调整到速度最大优化,编译环境为Visual Studio 2012,C++编译为32位,C#为Any CPU,运行于CORE i7。结果是运行10000次循环,算法相同的C++程序的速度大约是C#的6倍。当然这个倍率有点高于我的预料,可能程序中还有需要对针对C#进行改进和优化的地方(例如减少堆分配等),但同样C++也有提升空间(当然原作者已经做的很好了)。这个程序包含栈/递归和字典数据结构和一些逻辑和计算操作。总的来说在最大速度优先编译情况下,C++相对C#的执行效率优势还是比较明显。等过一阵子有空针对这个实例再做一次review和各自优化再评估一下结果。

 

关于效率这个问题,stackoverflow上有一些讨论可以参考:

http://stackoverflow.com/questions/145110/c-performance-vs-java-c

http://stackoverflow.com/questions/3961426/c-sharp-vs-c-performance-comparison

 

附,对应的C++程序(由原作者所作,略作修改并用于执行效率对比)

 

 

// HDU4090cpp.cpp : Defines the entry point for the console application.

//



#include "stdafx.h"





#include <stdlib.h>

#include <stdio.h>

#include <map>

#include <string>

#include <string.h>

#include <time.h>



using namespace std;

#define MAX 10





struct node {



    int x,y;

}qu[MAX*MAX];



map<string,int> _hash;

int gmmap[8][MAX][MAX];

int (*mmap)[MAX];

int ans;

int n,m,K,total;

int dir[8][2] = {{1,0},{1,1},{1,-1},{-1,0},{-1,-1},{-1,1},{0,1},{0,-1}};





void Print(int temp[][MAX],int n,int m) {



    for (int i = n-1; i >= 0; --i)

        for (int j = 0; j < m; ++j)

            printf("%d%c",temp[i][j],j==m-1?'\n':' ');

}

void change(int mmap[][MAX],int &n,int &m){



    int i,j,k[10],tn = 0,tm = 0;

    for (j = 0; j < m; ++j) {

        

        k[j] = 0;

        for (i = 0; i < n; ++i)

            if (mmap[i][j]) mmap[k[j]++][j] = mmap[i][j];

    }

    for (j = 0; j < m; ++j) 

        if (k[j]) {

            

            for (i = 0; i < k[j]; ++i)

                mmap[i][tm] = mmap[i][j];

            for (i = k[j]; i < n; ++i)

                mmap[i][tm] = 0;

            tm++;

            if (k[j] > tn) tn = k[j];

        }

    n = tn,m = tm;

}

int Ok(int temp[][MAX],int vis[][MAX],int i,int j,int n,int m) {



    int cnt = 0,k;

    int head = 0,tail = 0;

    node cur,next;





    cur.x = i,cur.y = j;

    qu[head++] = cur;

    vis[cur.x][cur.y] = 1;





    while (tail < head) {



        cur = qu[tail++];

        cnt++;

        for (k = 0; k < 8; ++k) {



            next.x = cur.x + dir[k][0];

            next.y = cur.y + dir[k][1];

            if (next.x >= 0 && next.x < n

                    && next.y >= 0 && next.y < m

                    && vis[next.x][next.y] == 0

                    && temp[next.x][next.y] == temp[i][j]) {



                qu[head++] = next;

                vis[next.x][next.y] = 1;

                temp[next.x][next.y] = 0;

            }

        }

    }

    temp[i][j] = 0;

    return cnt >= 3 ? cnt :  0;

}

string Get_hash(int temp[][MAX],int n,int m) {



    string s = "";

    for (int i = 0; i < n; ++i)

        for (int j = 0; j < m; ++j)

            s += temp[i][j] + '0';

    return s;

}

void mem(int temp[][MAX],int mmap[][MAX],int n,int m) {



    memset(temp,0,sizeof(temp));

    for (int i = 0; i < n; ++i)

        for (int j = 0; j < m; ++j)

            temp[i][j] = mmap[i][j];

}

int Dfs(int mmap[][MAX],int n,int m) {



    if (n * m < 3)  return 0;

    int temp[MAX][MAX],i,j;

    int vis[MAX][MAX],cnt = 0,ans;

    memset(vis,0,sizeof(vis));





    for (i = 0; i < n; ++i)

        for (j = 0; j < m; ++j)

            if (!vis[i][j] && mmap[i][j]) {



                mem(temp,mmap,n,m);

                ans = Ok(temp,vis,i,j,n,m);

                if (ans >= 3) {



                    ans = ans * ans;

                    int tn = n,tm = m;

                    change(temp,tn,tm);

                    string s = Get_hash(temp,tn,tm);

                    if (_hash.find(s) == _hash.end()) 

                         ans += Dfs(temp,tn,tm);

                    else ans += _hash[s];

                    if (ans > cnt) cnt = ans;

                }

            }





     _hash[Get_hash(mmap,n,m)] = cnt;

     return cnt;

}



int _tmain(int argc, _TCHAR* argv[])

{

	int i,j,k;

	int key[] = {166,36,94,128,896,4096};

	int t=0;

	FILE *fp = fopen("D:\\temp\\samples.txt", "r");

	int testnum = 0;

	while (fscanf(fp, "%d%d%d",&n,&m,&K) != EOF) 

	{

		for (i = n-1; i >= 0; --i)

			for (j = 0; j < m; ++j)

				fscanf(fp, "%d",&gmmap[testnum][i][j]);

		testnum++;

	}

	

	time_t t1;

	time(&t1);



	for (int C = 0; C < 10000; C++)

	{

		t = 0;

		for (int t=0; t<testnum; t++)

		{

			_hash.clear();

			int res = Dfs(gmmap[t],n,m);

			if (res != key[t])

			{

				printf("error\n");

				return 0;

			}

		   t++;

		}

	}

	time_t t2;

	time(&t2);

	double diff=difftime(t2,t1);

	printf("done %f\n", diff);

	fclose(fp);

}

你可能感兴趣的:(C++)