7.14.1. Selection Sort

array, selection sort, run order, big O notation, swap

Selection sort is small, relatively easy to understand and implement, and works well for small arrays (a few tens of elements). These characteristics make it an excellent example of array use, but it is sensitive to data size. Computer scientists use Big O notation to express an algorithm's general runtime as a function of data size. Using this notation, Selection sort's runtime is O(n2), which means that doubling the data size quadruples the time needed to sort it. Faster sorting algorithms, such as quicksort, are desirable for processing larger data sets.

The selection sort selects the smallest value in an array, swaps it with the element at the top, and logically moves the top down by one element. It repeats this cycle until the array size is 0 and the array is sorted. The algorithm can also select the largest element and swap it with the bottom element. Selection sort doesn't physically change the array size; instead, it maintains an index to the top (or bottom) that divides the array into two subarrays: sorted and unsorted. For simplicity, the following descriptions refer to the unsorted subarray as "the" subarray.

The selection sort requires two nested loops.
  • The outer loop drives the inner loop, moves the top down, and swaps the selected and top elements.
  • The inner loop selects the smallest element in the subarray.
for (int top = 0; top < size; top++)
{
    int min = top;

    for(int i = top + 1; i < size; i++)
        if (data[i] < data[min])
            min = i;
     // swap min and top
}
The selection sort structure. A single loop processing an array requires time proportional to the array's size, resulting in a big O of O(n). To understand the effect of nesting loops, imagine printing a square, two-dimensional array: the outer loop selects row, while the inner loop prints each element in a row (see the previous multtab.cpp example). The number of elements in a square array is n × n, and since the runtime is proportional to the number of elements, the big O is O(n2). Like the previous pyramid program, the starting point of the inner loop depends on the current state of the outer loop.

 

A picture illustrating a subarray or part of an array. The inner for-loop has identified the smallest element in the subarray. With the top and smallest (min) elements identified, the swap operation runs. The algorithm copies the smallest (min) element to temp. The algorithm copies the top element to the min location. temp is copied to the top location.
(a)(b)(c)(d)
Swapping the smallest and top elements. Swapping the elements of an array is an authentic application of the original swapping solution outlined in Chapter 1. topis an index pointing to the element at the top of the current subarray (green) and min is the index of the smallest (blue) element.
  1. The array at the beginning of a swap operation. The unsorted subarray lies between the top index and the end of the array. The inner loop locates the smallest element in the subarray and sets the min index.
  2. The swapping process requires a temporary variable, temp. The copies or saves the smallest element in the temporary variable.
  3. In a sense, saving the smallest array element "frees" that location in the array. The process copies or saves the top element in this now "free" or "empty" location.
  4. Finally, the process copies the temporary variable to the top of the subarray.
You can view steps (b), (c), and (d) as a cycle that can run either clockwise or counterclockwise.

Selection Sort With Fundamental Data

array, selection sort, ssort, sizeof, pass by pointer, pass by reference

The following functions demonstrate the selection sort with an array of characters, but the syntax works with any fundamental type (e.g., int or double),

DriverSelection Sort
#include <iostream>
using namespace std;

void ssort(char* data, int size);

int main()
{
    char data[] = { 'S','E','E','T','H','E','Q','U',
        'I', 'C','K','R','E','D','F','O','X' };
    int	size = sizeof(data) / sizeof(char);

    ssort(data, size);

    for (int i = 0; i < size; i++)
        cout << data[i] << endl;

    return 0;
}
void ssort(char* data, int size)
{
    for (int top = 0; top < size; top++)	// (a)
    {
        // select
        int min = top;				// (b)
        for (int i = top + 1; i < size; i++)	// (c)
            if (data[i] < data[min])		// (d)
                min = i;			// (e)

        // swap
        char temp = data[min];			// (f)
        data[min] = data[top];			// (g)
        data[top] = temp;			// (h)
    }
}
 
 
The selection sort function and driver. The driver defines an array of test data, counts its elements, calls the selection sort function, and prints the sorted data. Programmers can only place the statement counting the array elements with sizeof in the function where they define the array. sizeof counts the number of bytes in its operand. In the driver, data is an array, and sizeof returns the total number of bytes it uses. However, the driver passes the array as a function argument to ssort, making data a pointer whose size is typically 4 or 6 bytes.

The outer for-loop manages the subarray, applying the selection operation, swapping array elements, and shrinking the subarray with each iteration. The inner loop initially selects the top subarray element and compares it to the remaining elements, saving or selecting the index location of the smallest.

 

Pass By PointerPass By Reference
void swap(char* min, char* top);	// prototype

void ssort(char* data, int size)
{
    for (int top = 0; top < size; top++)
    {
        // select
        int min = top;
        for(int i = top + 1; i < size; i++)
            if (data[i] < data[min])
                min = i;

        swap(&data[min], &data[top]);
    }
}

void swap(char* min, char* top)
{
    char temp = *min;
    *min = *top;
    *top = temp;
}
void swap(char& min, char& top);	// prototype

void ssort(char* data, int size)
{
    for (int top = 0; top < size; top++)
    {
        // select
        int min = top;
        for(int i = top + 1; i < size; i++)
            if (data[i] < data[min])
                min = i;

        swap(data[min], data[top]);
    }
}

void swap(char& min, char& top)
{
    char temp = min;
    min = top;
    top = temp;
}
Selection sort with a swap function. Programs always pass arrays by pointer, but they can pass the individual elements using any passing mechanism. Moving the swapping statements to a separate function saves little space; however, it provides a significant conceptual shift, allowing programmers to focus on what the function does rather than how it does it.

Contemporary compilers often simplify pass by pointer by automatically typecasting function arguments to a pointer, making the address-of operator unnecessary. Consequently, programmers can simplify the pass-by-pointer function call in the first example to

swap(data[min], data[top]);

Selection Sort With Object Data

array, selection sort, ssort, sizeof, struct, pass by pointer, pass by reference
Review
student.hclient
struct student
{
    const char*  name;
          int    id;
          double gpa;
};

void ssort(student* data, int size);
#include <iostream>
#include <iomanip>
#include "student.h"
using namespace std;

int main()
{
    student students[] = {
            { "Dilbert", 123, 3.5 },
            { "Wally", 456, 2.0 },
            { "Alice", 987, 3.9 },
            { "Asok", 730, 3.8 },
            { "Catbert", 501, 3.0 },
            { "Pointy Haired Boss", 666, 1.0 },
            { "Dogbert", 111, 4.0 }
        };
    int    size = sizeof(students) / sizeof(student);

    ssort(students, size);

    cout.precision(1);			// formats gpa
    cout.setf(ios::left | ios::fixed);

    for (int i = 0; i < size; i++)
        cout << left << setw(5) << students[i].id <<
            setw(20) << students[i].name <<
            right << setw(5) << students[i].gpa << endl;

    return 0;
}
ssort.cpp
#include "student.h"

void ssort(student* data, int size)
{
    for (int top = 0; top < size; top++)
    {
        // select
        int min = top;
        for(int i = top + 1; i < size; i++)
            if (data[i].id < data[min].id)
                min = i;

        // swap
        student temp = data[min];
        data[min] = data[top];
        data[top] = temp;
    }
}
Sorting objects with selection sort. Programmers can use selection sort to sort arrays of objects (instances of structures or classes) based on one or more fields. The comparison operation, the if-statement in blue, extracts and compares the relevant fields. The less-than operator is sufficient for comparing fields consisting of fundamental data, but a comparison or ordering function is required for more complex types. For example, to sort an array of student objects by name, programmers would use the strcmp function:
if (strcmp(data[i].name, data[min].name) < 0)

 

Pass By PointerPass By ReferencePass The Data Array
void ssort(student* data, int size)
{
        . . . .
    swap(&data[top], &data[min]);
}
void swap(student* e1, student* e2)
{
    student temp = *e2;
    *e2 = *e1;
    *e1 = temp;
}
void ssort(student* data, int size)
{
        . . . .
    swap(data[top], data[min]);
}
void swap(student& e1, student& e2)
{
    student temp = e2;
    e2 = e1;
    e1 = temp;
}
void ssort(student* data, int size)
{
        . . . .
    swap(data, top, min);
}
void swap(student* data, int e1, int e2)
{
    student temp = data[e1];
    data[e1] = data[e2];
    data[e2] = temp;
}
Object versions of ssort and swap. Chapter 6 demonstrated pass-by-reference and pass-by-pointer versions of the swap function. The sorting logic is the same for arrays of fundamental data and objects. Furthermore, if the objects don't contain pointers, the swapping function is also the same because the assignment operator copies them completely. Chapter 10 addresses copying objects that do contain pointers. The swap function call in the pass-by-pointer version of ssort can also rely on the same automatic typecasting illustrated in Figure 4.

The last example demonstrates another option: passing the data array to the swap function. Whereas the other examples pass two array elements to the swap function, this version passes the entire array and two array indexes. Although the program passes the entire array, the function doesn't need the array's size and assumes that the two index values are within bounds.