分段 排序函数实现中的错误

Segmentation Fault in the implementation of a sorting function

本文关键字:错误 实现 排序 函数 分段      更新时间:2023-10-16

我正在尝试实现一种基于为我的编程课提供的伪代码的排序算法,我和我的搭档一直收到(核心转储(错误,通常是分段错误。我知道这通常意味着程序正在尝试访问不允许的内存,但我不确定如何解决这个问题。

#include <iostream>
#include <cmath>
using namespace std;
void FlipFlopSort(int *Array, int begin, int end){
int length = (end-begin);
float midh = 2*(float)length/3;
midh = ceil(midh);
float midl = (float)length/3;
midl = ceil(midl);
//cout << "size of sorted area = " << length << endl;
if(length<=2){
//cout << "Length = 2" << endl;
if(Array[begin] > Array[begin+1]){
swap(Array[begin], Array[begin+1]);
}
}else{
//cout << "Recursion Begin 1" << endl;
FlipFlopSort(Array, begin, midh);
//cout << "Recursion End" << endl;
FlipFlopSort(Array, midl, end);
//cout << "Recursion Begin 2" << endl;
FlipFlopSort(Array, begin, midh);
}
}
int main(){
// Declare Variables and Read Inputs
int n;
cin >> n;
int Array[n];
for(int i = 0; i < n; i++){
cin >> Array[i];
}
FlipFlopSort(Array, 0, n);

for(int i = 0; i<n; i++){
if(i != (n-1)){
cout << Array[i] << " ";
}else{
cout << Array[i] << endl;
}
}
return 0;
}

让我们从:

int n;
cin >> n;
int Array[n];
  1. 为什么 n 是有符号类型?数组大小不能声明为有符号类型。
  2. C++严格禁止在堆栈上声明可变大小的数组(即你所做的方式(。它也是 C 的一个已弃用的功能。你应该写:
int* Array = new int[n];

您可能遇到分段错误的原因之一是由于以下行:

if (length <= 2) {
//cout << "Length = 2" << endl;
if (Array[begin] > Array[begin + 1]) {
swap(Array[begin], Array[begin + 1]);
}
}
  1. 如果长度小于或等于 2,是否意味着它至少有 2 个元素?它可能有 0 或 1。您应该在函数的开头添加一个检查:
void FlipFlopSort(int *Array, int begin, int end){
int length = (end-begin);
if (length <= 1) {
return;
}
...
}

另一个原因是,因为您计算的是中间大小而不是索引,这意味着您不会向它们添加开头。

考虑:开始=100,结束=103。 -> 长度 = 3,midl = 1,midh = 2。意义?不!在这种情况下,这些不是有效的索引。你应该写的

midh += begin;
midl += begin;

经过他们的计算。

最后,你应该避免使用浮点数(除非你真的需要(,所以我会写:

const int midl = begin + length / 3;
const int midh = begin + 2 * midl;

它不等同于你写的,但它仍然有效,而你的是有风险的(上限值是可疑的,因为你可能会发现自己在数组的末尾(。

void FlipFlopSort(int* Array, int begin, int end) {
const int length = end - begin;
if (length <= 1) {
return;
}
const int midh = begin + 2 * length / 3;
const int midl = begin + length / 3;
//cout << "size of sorted area = " << length << endl;
if (length <= 2) {
//cout << "Length = 2" << endl;
if (Array[begin] > Array[begin + 1]) {
swap(Array[begin], Array[begin + 1]);
}
}
else {
FlipFlopSort(Array, begin, midh);
FlipFlopSort(Array, midl, end);
FlipFlopSort(Array, begin, midh);
}
}

您必须确保lengthswap时至少为 2,否则您将交换出界的数字。您的midl值和midh值当前是错误的。它们是相对于begin,因此您需要向它们添加begin。但是,您可以将midl添加到Array本身,并跳过函数中的begin参数以简化界面。

我还会将浮点std::ceil运算替换为整数版本。

// A function to do integer division and return the ceil value
size_t DivCeil(size_t dividend, size_t divisor) {
return 1U + ((dividend - 1U) / divisor);
}
void FlipFlopSort(int* Array, size_t length) {
if(length > 2) {
// calculate midl & midh
size_t midl = DivCeil(length, 3U);
size_t midh = DivCeil(2U * length, 3U);
FlipFlopSort(Array, midh);
// add midl to Array and sub midl from length
FlipFlopSort(Array + midl, length - midl);
FlipFlopSort(Array, midh);
} else if(length == 2) {
if(Array[1] < Array[0]) {
// swap the values
std::swap(Array[0], Array[1]);
}
} // else length < 2 ... don't do anything
}
#include <iostream>
#include <vector>
int main() {
size_t n;
if(std::cin >> n) { // check that the user entered a number
// don't use VLA:s, use a std::vector instead
std::vector<int> Array(n);
for(size_t i = 0; i < Array.size(); ++i) {
std::cin >> Array[i];
}
FlipFlopSort(Array.data(), Array.size());
for(int value : Array) {
std::cout << value << 'n';
}
}
}

如果您希望排序算法更加通用并可用于标准容器,则可以将输入参数替换为迭代器。

例:

#include <algorithm> // std::iter_swap
#include <iterator>  // std::distance, std::next
// A function to do integer division and return the ceil value
template<typename T>
T DivCeil(T dividend, T divisor) {
return 1 + ((dividend - 1) / divisor);
}
template<typename It>
void FlipFlopSort(It begin, It end) {
auto length = std::distance(begin, end);     // iterator version of "length = end-begin"
static constexpr decltype(length) two = 2;   // constant of the same type as length
static constexpr decltype(length) three = 3; // -"-
if(length > two) {
// calculate midl & midh iterators
auto midl = std::next(begin, DivCeil(length, three));
auto midh = std::next(begin, DivCeil(two * length, three));
FlipFlopSort(begin, midh);
FlipFlopSort(midl, end);
FlipFlopSort(begin, midh);
} else if(length == two) {
if(*std::next(begin) < *begin) {
// swap the values pointed at by the iterators
std::iter_swap(begin, std::next(begin));
}
} // else length == 1 or 0 ... don't do anything
}

用法:

#include <iostream>
#include <vector>
int main() {
size_t n;
if(std::cin >> n) {
std::vector<int> Array(n);
for(size_t i = 0; i < Array.size(); ++i) {
std::cin >> Array[i];
}
FlipFlopSort(std::begin(Array), std::end(Array));
for(int value : Array) {
std::cout << value << 'n';
}
}
}