我正在制作一个小项目,逐步展示不同排序算法的工作原理。本质上只是一堆用 opengl 绘制的随机线,然后进行排序。为了显示我的步骤,在算法中的每次交换之后,我重绘屏幕并使程序休眠大约 5 毫秒。当使用调试器在 Visual Studio 中运行时,根本没有问题,但如果我在没有调试器的情况下运行,无论是使用 ctrl+f5
还是从 Windows 资源管理器中,显示都会冻结并停止在排序算法中途停止绘制(不管什么算法)——但是,控制台仍然会在最后输出信息(比较和交换的次数),并且根据需要多长时间,延迟确实仍然有效)。我已经缩小范围是因为睡眠功能,因为当我不使用睡眠时,它可以完美地工作,只是太快了。为了让事情变得更奇怪,我将 exe 发送给了一个朋友,对他来说没有问题。我还尝试将 _NO_DEBUG_HEAP
设置为 1 以查看是否可以在附加调试器的情况下捕获错误,但没有成功。
如果 Windows.h Sleep(x)
有一些奇怪的地方,我使用 ctime clock
类型/函数创建了自己的小函数,但仍然很奇怪,没有调试器错误继续存在。
我自己的睡眠功能:
void slp(clock_t wait)
{
clock_t goal;
goal = wait + clock();
while(goal > clock());
}
有什么可以解释为什么这对一个人(我的朋友)而不是我自己有效?下面包含了更多代码,尽管我不认为其中任何一个是问题,但我认为这只是我需要一种更好的方式来睡眠/延迟程序。
/*My window creation/drawing code, just in case its a glut issue some how
(normally I'd use glfw but couldn't get things like glRecti to work for the life of me)*/
constexpr int N = 320;
int heights[ N ];
void gfx();
int main(int argc, char** argv)
{
for (int i = 0; i < N; i++)
{
heights[ i ] = rand() % 600;
}
glutInit(&argc, argv);
glutInitWindowSize(1280, 720);
int cx = (glutGet(GLUT_SCREEN_WIDTH) - 1280) / 2;
int cy = (glutGet(GLUT_SCREEN_HEIGHT) - 720) / 2;
glutInitWindowPosition(cx, cy);
glutCreateWindow("Sorting Visualizer");
glutDisplayFunc(gfx);
glClearColor(0, 0, 0, 1);
gluOrtho2D(0, 1280, 0, 720);
glutMainLoop();
return 0;
}
gfx 函数很简单
void gfx()
{
glClear(GL_COLOR_BUFFER_BIT);
HeapSorter<int, N> heap(heights);
heap.sort();
heap.printInfo();
}
现在是排序算法:
template <typename T, int N>
class HeapSorter : public Sorter<T, N>
{
using Sorter<T, N>::drawStep;
using Sorter<T, N>::mSwaps;
using Sorter<T, N>::mCompares;
using Sorter<T, N>::mArr;
using Sorter<T, N>::mName;
public:
HeapSorter(T arr[ N ], int slp = 5) : Sorter<T, N>("Heap Sort", arr, slp) {}
void sort()
{
for (int i = N / 2 - 1; i >= 0; i--)
{
heapify(N, i);
}
for (int i = N - 1; i > 0; i--)
{
std::swap(mArr[ 0 ], mArr[ i ]);
mSwaps++;
drawStep();
heapify(i, 0);
}
}
private:
void heapify(const int n, int i)
{
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
++mCompares;
if (left < n && mArr[ left ] > mArr[ largest ])
{
largest = left;
}
++mCompares;
if (right < n && mArr[ right ] > mArr[ largest ])
{
largest = right;
}
if (largest != i)
{
std::swap(mArr[ i ], mArr[ largest ]);
++mSwaps;
drawStep();
heapify(n, largest);
}
}
};
超类只处理绘图,sleep函数发生在drawStep
template <typename T, int N>
class Sorter
{
public:
Sorter(std::string name, T arr[ N ], const int slp = 5) :
mName(std::move(name)),
mSleep(slp)
{
for (auto i = 0; i < N; i++)
{
mArr[ i ] = arr[ i ];
}
}
void printInfo() const
{
std::cout << mName << " - Compares: " << mCompares << " - Swaps: " << mSwaps << "\n";
}
protected:
static void drawText(const float x, const float y, const std::string& txt)
{
glColor3f(1, 1, 1);
glRasterPos2f(x, y);
for (auto i : txt)
{
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, i);
}
}
void drawStep()
{
glClear(GL_COLOR_BUFFER_BIT);
drawText(5, 700, mName);
drawText(5, 680, "Compares: " + std::to_string(mCompares));
drawText(5, 660, "Swaps: " + std::to_string(mSwaps));
drawText(5, 640, "Sleep: " + std::to_string(mSleep) + " ms");
glColor3f(1.f, 0.f, 0.f);
for (auto i = 0; i < N; i++)
{
glRecti(4 * i, 100, 4 * i + 3, 100 + mArr[ i ]);
}
glFlush();
SLP(mSleep);
}
std::string mName;
int mSleep;
int mCompares = 0;
int mSwaps = 0;
T mArr[ N ];
};
SLP
只是一个宏,因此我可以快速测试不同的睡眠功能,而无需更改我可能使用它的任何地方