如何在C++中实现带连接线的层级式排行榜可视化?
如何在C++中实现带连接线的层级式排行榜?
我尝试用vector实现层级排行榜,但排版不够规整,想添加如下样式的连接线,直到第31名:
Rank1 | +----------------------+-----------------------+ Rank2 Rank3 | | +----------+----------+ +--------+--------+ Rank4 Rank5 Rank6 Rank7
以下是我目前的代码:
#include <iostream> #include <vector> #include <string> using namespace std; // 打印一行获奖者 void printRow(const vector<string>& row, int totalWidth) { int elements = row.size(); int spaceBetween = (totalWidth - elements) / (elements + 1); for (int i = 0; i < elements; ++i) { for (int j = 0; j < spaceBetween; ++j) cout << " "; cout << row[i]; } cout << endl; } // 打印获奖者图表 void printWinnersChart() { vector<vector<string>> winnersChart = { {"Bob"}, {"Alice", "Charlie"}, {"David", "Eve", "Frank", "Grace"}, {"Henry", "Isabella", "Jack", "Kate", "Liam", "Mia", "Noah", "Olivia"}, {"Penelope", "Quinn", "Ryan", "Sophia", "Thomas", "Uma", "Victoria", "William", "Xavier", "Yara", "Zoe", "Adam", "Bella", "Caleb", "Diana", "Ethan"} }; int totalWidth = 80; for (const auto& row : winnersChart) { printRow(row, totalWidth); } } int main() { cout << "Figure 2: Sample of the winners' chart" << endl; printWinnersChart(); // 等待用户按回车退出终端 cin.get(); return 0; }
解决方案
要实现带连接线的层级式排行榜,核心是计算每一层每个元素的位置,再根据父子元素的位置关系绘制连接线。以下是修改后的完整代码:
#include <iostream> #include <vector> #include <string> using namespace std; // 存储元素的位置信息 struct ElementPos { string name; int start; // 元素起始坐标 int mid; // 元素中间坐标 }; // 打印一行元素并记录每个元素的位置 void printRowAndRecordPos(const vector<string>& row, int totalWidth, vector<ElementPos>& posList) { posList.clear(); int elementCount = row.size(); // 计算所有元素的总长度 int totalNameLen = 0; for (const string& name : row) { totalNameLen += name.size(); } // 计算元素间的间隔 int spaceBetween = (totalWidth - totalNameLen) / (elementCount + 1); int currentPos = spaceBetween; for (const string& name : row) { // 打印前置空格 cout << string(currentPos, ' '); cout << name; // 记录位置 ElementPos pos; pos.name = name; pos.start = currentPos; pos.mid = currentPos + name.size() / 2; posList.push_back(pos); // 更新下一个元素的起始位置 currentPos += name.size() + spaceBetween; } cout << endl; } // 打印当前行与下一行之间的连接线 void printConnectors(const vector<ElementPos>& upperPos, const vector<ElementPos>& lowerPos, int totalWidth) { // 第一行:上层元素的竖线 string line(totalWidth, ' '); for (const ElementPos& pos : upperPos) { line[pos.mid] = '|'; } cout << line << endl; // 第二行:横线与分叉点 line.assign(totalWidth, ' '); for (int i = 0; i < upperPos.size(); ++i) { int upperMid = upperPos[i].mid; // 找到当前上层元素对应的两个下层元素 int leftIdx = 2 * i; int rightIdx = 2 * i + 1; if (leftIdx >= lowerPos.size() || rightIdx >= lowerPos.size()) { continue; } int leftMid = lowerPos[leftIdx].mid; int rightMid = lowerPos[rightIdx].mid; // 绘制中间连接点 line[upperMid] = '+'; // 绘制左侧横线 for (int j = leftMid; j < upperMid; ++j) { line[j] = '-'; } // 绘制右侧横线 for (int j = upperMid + 1; j <= rightMid; ++j) { line[j] = '-'; } // 绘制左右连接点 line[leftMid] = '+'; line[rightMid] = '+'; } cout << line << endl; } // 打印完整层级排行榜 void printWinnersChart() { vector<vector<string>> winnersChart = { {"Bob"}, {"Alice", "Charlie"}, {"David", "Eve", "Frank", "Grace"}, {"Henry", "Isabella", "Jack", "Kate", "Liam", "Mia", "Noah", "Olivia"}, {"Penelope", "Quinn", "Ryan", "Sophia", "Thomas", "Uma", "Victoria", "William", "Xavier", "Yara", "Zoe", "Adam", "Bella", "Caleb", "Diana", "Ethan"} }; int totalWidth = 120; // 加宽总宽度适配多层级排版 vector<ElementPos> prevPos; for (size_t i = 0; i < winnersChart.size(); ++i) { vector<ElementPos> currentPos; printRowAndRecordPos(winnersChart[i], totalWidth, currentPos); // 非最后一行则打印连接线 if (i < winnersChart.size() - 1) { printConnectors(currentPos, prevPos, totalWidth); } prevPos = currentPos; } } int main() { cout << "Figure 2: 获奖者排行榜示例" << endl; printWinnersChart(); // 等待用户按回车退出 cin.get(); return 0; }
关键说明
- 位置记录:通过
ElementPos结构体记录每个元素的起始和中间坐标,这是精准绘制连接线的核心依据。 - 连接线逻辑:先绘制上层元素的竖线,再通过横线连接上层元素与对应的两个下层元素,用
+标记分叉点。 - 宽度适配:将总宽度设为120,避免层级增多后排版拥挤,可根据实际元素长度调整该值。
- 层级对应:默认每一层元素数量是上一层的2倍(符合示例中的层级规律),若你的层级结构不同,需调整
leftIdx和rightIdx的计算逻辑。
内容的提问来源于stack exchange,提问作者SaveSecure
相关产品推荐
相关产品推荐

