c# - 有没有办法增加c#中的堆栈大小?
问题描述
在几年没有做任何事情之后,我又回到了编程领域,并创建了一个数独游戏来让我的脚再次湿透。我编写了一个递归函数来蛮力解决方案,它会为简单的板状态执行此操作,但对于更复杂的板状态,大多数时间都会遇到堆栈溢出。我知道可以使用循环或更有效的算法来避免这种情况,但由于这是为了学习,我想知道如何为堆栈分配更多内存(承认这不是解决问题的最佳方法)。
这里有一个答案:如何更改 .NET 程序的堆栈大小?建议使用分配更多内存的线程不起作用,因为据我所知,.NET 4.0 不会让您将线程的最大分配内存增加到默认值之外。
另一种解决方案建议使用 EDITBIN.EXE,但我是 Visual Studio 的新手,还没有找到我理解的解释。
同样,我发现您可以使用 .def 文件来指示更大的默认堆栈大小,但没有找到我理解的关于如何创建/实现一个的解释。
任何人都可以提供 EDITBIN.EXE 或 .def 文件实现的新手级解释,或者提供另一种增加堆栈大小的方法吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Sudoku
{
//object keeps track of the value of all numbers currently on the board using an array
class BoardState
{
int testcount = 1;
//3d array of ints representing all values on the board, represted as region, column, row
int[,,] boardVals;
//3d array of bools representing if a number is immutable (true cannot be changed, false can be)
bool[,,] fixedVals;
//create a blank board if no initial values are provided
public BoardState()
{
boardVals = new int[9, 3, 3];
fixedVals = new bool[9, 3, 3];
}
//create a board with the listed initial values as immutable
public BoardState(int[,,] inputVals)
{
boardVals = inputVals;
fixedVals = new bool[9,3,3];
for (int i = 0; i < 9; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
if (boardVals[i, j, k] > 0) fixedVals[i, j, k] = true;
}
//update the state of the board using the coordinates of a single value
//**note** method has not been implemented and tested yet
public void updateState(int region, int column, int row, int val)
{
if (!fixedVals[region, column, row])
{
boardVals[region, column, row] = val;
}
}
//update the state of the board to match the state of another board
public void updateState(int[,,] newState)
{
boardVals = newState;
}
public int[,,] getVals()
{
return boardVals;
}
public bool[,,] getFixed()
{
return fixedVals;
}
//set all non-zero values to be immutable
public void setFixed()
{
for (int i = 0; i < 9; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) {
if (boardVals[i, j, k] != 0)
fixedVals[i, j, k] = true;
else
fixedVals[i, j, k] = false;
}
}
//test method
public void testState()
{
for (int i = 0; i < 9; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
Console.WriteLine(boardVals[i, k, j]);
}
//accepts a 3d array representing the current board state.
//returns a 3d bool array denoting whether any region, row, or column is invalid (true=invalid)
//first value of array designates the region, row, or column respectively
//second value designates which of those is invalid
public bool[,] validateBoard()
{
bool[,] valid = new bool[3, 9];
int[,] rows = makeRows(boardVals);
int[,] cols = makeCols(boardVals);
//compare each value in each row to each other value in that row
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (rows[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && rows[i, j] == rows[i, k])
valid[1, i] = true;
}
}
}
}
//compare each value in each column to each other value in that column
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (cols[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && cols[i, j] == cols[i, k])
valid[2, i] = true;
}
}
}
}
//compare each value in each region to each other value in that region
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
//only validate an entry if it has been assigned a value
if (boardVals[i, j, k] != 0)
{
for (int l = 0; l < 3; l++)
{
for (int m = 0; m < 3; m++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (!(l == j && m == k) && boardVals[i, j, k] == boardVals[i, l, m])
valid[0, i] = true;
}
}
}
}
}
}
return valid;
}
public bool isValid()
{
bool retFlag = true;
bool[,] valid = new bool[3, 9];
int[,] rows = makeRows(boardVals);
int[,] cols = makeCols(boardVals);
//for (int i = 0; i < 9; i++)
// for (int j = 0; j < 3; j++)
// for (int k = 0; k < 3; k++)
// Console.Write(boardVals[i, j, k]);
//compare each value in each row to each other value in that row
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (rows[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && rows[i, j] == rows[i, k])
{
retFlag = false;
}
}
}
}
}
//compare each value in each column to each other value in that column
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
//only validate an entry if it has been assigned a value
if (cols[i, j] != 0)
{
for (int k = 0; k < 9; k++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (j != k && cols[i, j] == cols[i, k])
{
retFlag = false;
}
}
}
}
}
//compare each value in each region to each other value in that region
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
//only validate an entry if it has been assigned a value
if (boardVals[i, j, k] != 0)
{
for (int l = 0; l < 3; l++)
{
for (int m = 0; m < 3; m++)
{
//if two values are not the same entry and are equal, set that entry to invalid
if (!(l == j && m == k) && boardVals[i, j, k] == boardVals[i, l, m])
{
retFlag = false;
}
}
}
}
}
}
}
return retFlag;
}
//returns an array of all the values in each row
public int[,] makeRows(int[,,] boardState)
{
int[,] rows = new int[9, 9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
rows[i, j] = boardState[j / 3 + ((i / 3) * 3), j % 3, i - ((i / 3) * 3)];
return rows;
}
//returns an array of all values in each column
public int[,] makeCols(int[,,] boardState)
{
int[,] cols = new int[9, 9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
cols[i, j] = boardState[((j / 3) * 3) + (i / 3), i - ((i / 3) * 3), j % 3];
return cols;
}
//update the board state to a state read in from a file
public void updateFromFile(Stream update)
{
int[,,] newVals = new int[9, 3, 3];
int[,,] newFixed = new int[9, 3, 3];
StreamReader file = new StreamReader(update);
for (int i = 0; i < 9; i++){
for (int j = 0; j < 3; j++){
for (int k = 0; k < 3; k++){
boardVals[i, j, k] = (int)char.GetNumericValue((char)file.Read());
}
}
}
for (int i = 0; i < 9; i++){
for (int j = 0; j < 3; j++){
for (int k = 0; k < 3; k++){
fixedVals[i, j, k] = (0 != ((int)char.GetNumericValue((char)file.Read())));
}
}
}
file.Close();
}
public void Solve(int entry, int val)
{
Console.WriteLine("This is call number " + ++testcount);
//returns if all values are filled and valid
if (entry == 81)
{
Console.WriteLine("Solved!");
return;
}
//creating reference coordinates based on entry value
int reg = entry / 9;
int col = (entry - (reg * 9)) % 3;
int row = (entry - (reg * 9)) / 3;
//if current entry being checked is a fixed value, go the next value
if (!fixedVals[reg, row, col])
{
Console.WriteLine("");
Console.WriteLine("Making an attempt at entry " + entry + " using value " + val);
Console.WriteLine("This entry is at region " + reg + ", col " + col + ", row " + row);
//assign entry the value to be tested
boardVals[reg, row, col] = val;
//if the value is valid, go to the next entry
if (isValid())
{
Console.WriteLine("Entry Valid at " + entry);
val = 1;
entry++;
Console.WriteLine("Trying the next entry at " + entry);
Solve(entry, val);
}
//if the value is invlid and all 9 values have not been tried,
//increment value and call again at same entry
if (!isValid() && val < 9)
{
Console.WriteLine("Entry Invalid at " + entry + " with value " + val);
++val;
Console.WriteLine("Trying again with value " + val);
Solve(entry, val);
}
//if the value in invalid and all 9 values have been tried,
//zero out the entry and go back to the previous non-fixed entry
if (!isValid() && val == 9)
{
do
{
boardVals[reg, row, col] = 0;
Console.WriteLine("Reached Value 9 and was still invalid");
--entry;
Console.WriteLine("Trying again at entry " + entry);
Console.WriteLine("The value at that entry is " + boardVals[reg, row, col]);
reg = entry / 9;
col = (entry - reg * 9) % 3;
row = (entry - reg * 9) / 3;
if (fixedVals[reg, row, col])
Console.WriteLine("But that's a fixed value, so I'll go back one more");
Console.WriteLine("");
} while (boardVals[reg, row, col] == 9 || fixedVals[reg, row, col]);
val = boardVals[reg, row, col] + 1;
Solve(entry, val);
}
}
else Solve(++entry, val);
}
}
}
解决方案
严重的警告
如果您在程序中使用递归并达到 StackOverflowException 是一个实际威胁的程度,请不要将增加堆栈大小作为有效的解决方案。
如果你遇到 StackOverflowException,你就做错了;您应该改为使用Stack<T>
深度优先处理或Queue<T>
广度优先处理。例子。
解决方案
这可以通过使用editbin.exe
与此软件包一起安装的 来实现;
找到 的位置editbin.exe
,我的位置是C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\editbin.exe
,我建议使用voidtools的 Everything 代替微软可怕的搜索来找到这个。
手动设置堆栈大小
导航到您的 bin 文件夹并执行以下命令:
"<full path of editbin.exe>" /stack:<stack size in bytes, decimal> <your executable name>
例如我执行了这个:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\EDITBIN.EXE" /stack:2097152 ExampleProgram.exe
它将堆栈保留大小设置为 2MB。
有了这个,我能够达到两倍的递归水平;(左侧为 1MB 堆栈预留,右侧为 2MB 堆栈预留)。
自动设置堆栈大小
右键单击您的项目并选择“选项”,然后单击“构建事件”并将以下内容添加到您的构建后事件中:
"<full path of editbin.exe>" /stack:<stack size in bytes, decimal> "$(TargetPath)"
例如我添加了
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\EDITBIN.EXE" /stack:2097152 "$(TargetPath)"
这将在editbin.exe
您每次构建可执行文件时运行。
注意:当您从 Visual Studio 运行程序时,您将看到低得多的递归级别,就像您通过资源管理器或 cmd 显式运行它一样。但是,如果从 1MB 堆栈保留移动到 2MB 堆栈保留,您仍然会看到递归级别增加 2 倍。
推荐阅读
- javascript - 创建一个网络表单,我可以将 excel 行/列粘贴到
- python - 使用带有双引号的某些键和值从 python 生成 YAML 文件
- spring - JMS 的 Spring Tomcat 配置(IBM MQ、Tomcat、Spring)
- c# - 如何设置 Observable 来观察属性?
- postgresql - 如何在 postgresql 9.2 中将表设置为 LOGGED?
- sql - "\N" 在 case when 语句中
- c - 当输入小于最大整数数时,代码不会运行
- python - int 对象不可下标,但它是一个列表
- java - 为什么使用 "" 而不是 ' ' 来输出空白?
- python - 为什么我不能在 jupyter python 中为输入函数运行两次代码?