C++自定义排序(pred)异常:线段端点反转问题求助
问题根源与解决方案
这个问题的核心在于你忽略了线段的无向性——同一条线段可以用两种端点顺序来表示(比如[0, 368, 639, 310]和[639, 310, 0, 368]其实是同一条线段),但你的排序逻辑只盯着每条线段的第一个端点的坐标来比较,这就导致原本是同一条线段的不同写法,在排序时被当成了完全不同的元素,出现了你看到的端点互换的混乱情况。
具体原因
你的linesSort结构体只比较两条线段的第一个端点:
- 对于
[0, 368, 639, 310],第一个端点是(0,368),x=0 - 对于
[639, 310, 0, 368],第一个端点是(639,310),x=639
所以前者会被排在前面,后者会被排到后面,但它们本质是同一条线段,看起来就像是排序后出现了端点互换的异常。
解决方法
我们需要先统一所有线段的端点表示,确保每条线段的第一个端点都是“更小”的那个(先比x,x相同再比y),然后再进行排序。这样同一条线段的两种写法会被转换成完全相同的形式,排序时就不会出现混乱。
步骤1:预处理线段,统一端点顺序
先写一个函数来标准化每条线段的端点:
// 标准化线段:确保第一个端点的(x,y) <= 第二个端点的(x,y) void normalizeLine(cv::Vec4i& line) { int x1 = line[0], y1 = line[1]; int x2 = line[2], y2 = line[3]; // 如果第二个端点的坐标更小,就交换两端点 if (x2 < x1 || (x2 == x1 && y2 < y1)) { std::swap(line[0], line[2]); std::swap(line[1], line[3]); } }
步骤2:预处理所有线段后再排序
先遍历所有线段完成标准化,再执行排序:
// 先统一所有线段的端点表示 for (auto& line : lines) { normalizeLine(line); } // 再执行排序(此时可以用原逻辑,或者简化的lambda表达式) std::sort(lines.begin(), lines.end(), [](const cv::Vec4i& l1, const cv::Vec4i& l2) { int x1 = l1[0], y1 = l1[1]; int x2 = l2[0], y2 = l2[1]; if (x1 == x2) { return y1 < y2; } return x1 < x2; });
效果验证
经过预处理后,原本的[639, 310, 0, 368]会被转换成[0, 368, 639, 310],和另一条同线段的表示完全一致,排序时它们会被视为相同元素(如果去重的话也能轻松处理),不会再出现你看到的端点互换的混乱情况。
内容的提问来源于stack exchange,提问作者PHAN LE HOANG VIET
相关产品推荐
相关产品推荐

