Reputation: 21
I have the following code to implement insertion sort:
int main()
{
const int SIZE = 10;
int a[SIZE] = {8, 6, 10, 2, 16, 4, 18, 14, 12, 10};
//insertionSort(a, SIZE);
// The following code is used in the insertionSort() function call above. To use the function, uncomment the function call above, and comment out the code below
// Start of code used by insertionSort() function
int temp;
for (int i=1; i < SIZE; i++)
{
for (int j=i; a[j] < a[j-1]; j--)
{
temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
}
// End of code used by insertionSort() function
return 0;
}
void insertionSort(int a[], const int SIZE)
{
int temp;
for (int i=1; i < SIZE; i++)
{
for (int j=i; a[j] < a[j-1]; j--)
{
temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
}
}
The algorithm works fine when the code is used in main(), but it produces wrong results when it's called via insertionSort().
I've determined that the issue is this: the inner loop condition (a[j] < a[j-1]) does not stop the loop when j reaches 0, so it continues to access the array using the negative index. Changing the condition to (j > 0 && a[j] < a[j-1]) works as expected.
I would like to know why this behaviour only exhibits when the loop runs inside insertionSort() but not when it runs in main().
Upvotes: 1
Views: 87
Reputation: 311058
This loop
for (int j=i; a[j] < a[j-1]; j--)
{
temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
invokes undefined behavior because there is no check that j
shall be greater than 0
.
Otherwise when for example j
is equal to 0
then there is access beyond the array using the index -1
a[0] < a[-1]
Here is a demonstrative program with the updated loop
#include <iostream>
#include <utility>
int main()
{
int a[] = { 8, 6, 10, 2, 16, 4, 18, 14, 12, 10 };
const size_t SIZE = sizeof( a ) / sizeof( *a );
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
for ( size_t i = 1; i < SIZE; i++ )
{
for ( size_t j = i; j != 0 && a[j] < a[j-1]; --j )
{
std::swap( a[j-1], a[j] );
}
}
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Its output is
8 6 10 2 16 4 18 14 12 10
2 4 6 8 10 10 12 14 16 18
And including the algorithm in a function
#include <iostream>
#include <utility>
void insertionSort( int a[], size_t n )
{
for ( size_t i = 1; i < n; i++ )
{
for ( size_t j = i; j != 0 && a[j] < a[j-1]; --j )
{
std::swap( a[j-1], a[j] );
}
}
}
int main()
{
int a[] = { 8, 6, 10, 2, 16, 4, 18, 14, 12, 10 };
const size_t SIZE = sizeof( a ) / sizeof( *a );
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
insertionSort( a, SIZE );
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The output is the same as shown above
8 6 10 2 16 4 18 14 12 10
2 4 6 8 10 10 12 14 16 18
Upvotes: 3