数据结构——六种Sort方法的代码实现

本文基于《Data Structures and Program Design in C++》一书,详细介绍了六种经典的排序算法,并提供了C++代码实现,包括选择排序、插入排序、冒泡排序、快速排序、归并排序和堆排序。通过实例解析,帮助读者深入理解各种排序算法的工作原理及其应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Reference Book: 《Data Structures and Program Design in C++》

---------------------------------------------------------------------------------------------------------------------------------------------------
1. Doubly_Linked_List
    见文章《Doubly_Linked_List的代码实现》

2. Sortable_list
#ifndef SORTABLE_LIST_H
#define SORTABLE_LIST_H

#include "Doubly_Linked_List.h"
#include "Record.h"

#define MAX_SIZE 128

template <class Key>
class Sortable_list: public Doubly_Linked_List<Key>
{
    public:
        //直接调用基类Doubly_Linked_List的初始化方法
        // 插入排序
        void insertion_sort();

        // 选择排序
        void selection_sort();
        int max_key(int low, int high);
        void swap(int low, int high);

        // 希尔排序(不适用链式实现)
        void sort_interval(int start, int increment);
        void shell_sort();

        // 归并排序
        void merge_sort();
        void recursive_merge_sort(Sortable_list<Key> &the_list);
                // 不用书中传入head指针的实现方式
        Sortable_list<Key> divide_from(Sortable_list<Key> &the_list);
        void combine(Sortable_list<Key> &the_list,
                     const Sortable_list<Key> &second_list);

        // 快速排序
        void quick_sort();
        void recursive_quick_sort(Sortable_list<Key> &the_list);
        Sortable_list<Key> partition(Sortable_list<Key> &the_list,
                                     Key pivot);
        void unite(Sortable_list<Key> &the_list,
                   Sortable_list<Key> &second_list,
                   Key pivot);

        // 堆排序
        void heap_sort();
        void build_heap();
        void insert_heap(const Key &now, int low, int high);
        void insert_array(int position, const Key &data);
        void traverse_array(void (*visit)(Key &));

    protected:

    private:
        Key entry[MAX_SIZE];

};


/*************************************
*            Insertion Sort          *
*************************************/
template <class Key>
void Sortable_list<Key>::insertion_sort()
/*Pre:
  Post: 从前向后遍历表, 将尚未排序的第一个键在已排序队列中找到合适的位置进行插入.
*/
{
    Node<Key> *first_unsorted, *last_sorted, *now, *trailing;
    if(Doubly_Linked_List<Key>::head != nullptr)  // head是双链表类中的元素, 需要作用域符号
    {
        last_sorted = Doubly_Linked_List<Key>::head;
        while(last_sorted->next != nullptr)
        {
            first_unsorted = last_sorted->next;
            // 插入到pos==0的位置
            if(first_unsorted->entry <= Doubly_Linked_List<Key>::head->entry)
            {
                last_sorted->next = first_unsorted->next;
                if(first_unsorted->next != nullptr)    // 当unsorted中至少有1个结点时
                    first_unsorted->next->back = last_sorted;
                Doubly_Linked_List<Key>::head->back = first_unsorted;
                first_unsorted->next = Doubly_Linked_List<Key>::head;
                first_unsorted->back = nullptr;
                Doubly_Linked_List<Key>::head = first_unsorted;
            }
            // 搜索正确的pos插入
            else
            {
                trailing = Doubly_Linked_List<Key>::head;
                now = trailing->next;
                while(first_unsorted->entry > now->entry)
                {
                    trailing = now;
                    now = trailing->next;
                }
                if(first_unsorted==now) // 已经在正确的位置
                    last_sorted = first_unsorted;
                else
                {
                    last_sorted->next = first_unsorted->next;
                    first_unsorted->next->back = last_sorted;
                    first_unsorted->next = now;
                    now->back = first_unsorted;
                    trailing->next = first_unsorted;
                    first_unsorted->back = trailing;
                }
            }
        }
    }
}



/*************************************
*            Selection Sort          *
*************************************/
template <class Key>
void Sortable_list<Key>::selection_sort()
/*Pre:
  Post:
*/
{
    // pos从最后到1, 不用到0因为pos==1时已经比较过第一个键
    for(int pos = Doubly_Linked_List<Key>::count-1; pos > 0; pos--)
    {
        int max = max_key(0, pos);
        swap(max, pos);
    }
}

template <class Key>
int Sortable_list<Key>::max_key(int low, int high)
/*Pre:
  Post: 遍历pos从low到high之间的所有键, 返回最大键的位置.
*/
{
    Key data, now_entry;
    Doubly_Linked_List<Key>::set_position(low);
    data = Doubly_Linked_List<Key>::current->entry;
    int now, pos = low;
    // 找到pos为low至high之间最大键的位置
    for(now = low + 1; now <= high; now++)
    {
        Doubly_Linked_List<Key>::set_position(now);
        now_entry = Doubly_Linked_List<Key>::current->entry;
        if(data < now_entry)
        {
            data = now_entry;
            pos = now;
        }
    }
    return pos;
}

template <class Key>
void Sortable_list<Key>::swap(int low, int high)
/*Pre:
  Post: 若需要交换的pos相同者不进行操作; 否则通过insert和remove操作先将最大键插入到
        pos==high的位置, 再删除对应结点, 再将要交换的键插入到pos==low的位置, 最后
        remove该键注意该键在high+1的位置.
*/
{
    if(low==high)return;  // 当前pos的键为最大键则不发生交换

    Key data;
    Node<Key> *max, *pos;
    Doubly_Linked_List<Key>::set_position(low);
    max = Doubly_Linked_List<Key>::current;
    Doubly_Linked_List<Key>::set_position(high);
    pos = Doubly_Linked_List<Key>::current;

    // 利用insert和remove操作完成结点的交换
    (*this).insert(high, max->entry);
    (*this).remove(low, data);
    (*this).insert(low, pos->entry);
    (*this).remove(high+1, data);
}


/*********************************
*            Shell Sort          *
*********************************/
template <class Key>
void Sortable_list<Key>::sort_interval(int start, int increment)
/*Pre:
  Post:
*/
{
    int first_unsorted; // position of first unsorted entry
    int position; // searches sorted part of list
    Key current; // holds the entry temporarily removed from list
    for (first_unsorted = start + increment; first_unsorted <
         Doubly_Linked_List<Key>::count; first_unsorted += increment )
    if (entry[first_unsorted] < entry[first_unsorted - increment]) {
        position = first_unsorted;
    current = entry[first_unsorted]; // Pull unsorted entry out of the list.
    do { // Shift all entries until the proper position is found.
        entry[position] = entry[position - increment];
        position -= increment; // position is empty.
    } while (position > start && entry[position - increment] > current);
    entry[position] = current;
    }
}

template <class Key>
void Sortable_list<Key>::shell_sort()
/*Pre:
  Post:
*/
{
    int increment, start;
    increment = Doubly_Linked_List<Key>::count;
    do
    {
        increment = increment/3+1;
        for(start = 0; start<increment; start++)
            sort_interval(start, increment);
    }while(increment > 1);
}


/**********************************
*            Merge Sort           *
**********************************/
template <class Key>
void Sortable_list<Key>::merge_sort()
/*Post: 对表中元素分组重新排列,最终得到一个升序序列.
  Uses: Doubly_Linked_List和recursive_merge_sort().
*/
{
    recursive_merge_sort(*this);
}

template <class Key>
void Sortable_list<Key>::recursive_merge_sort(Sortable_list<Key> &the_list)
/*Post: 通过将the_list分为两个子表再递归调用recursive_merge_sort()并将其合并, 通过
        修改the_list返回排序后的新表.
  Uses:
*/
{
    Sortable_list<Key> second_list;
    if(the_list.size() > 1)  // 表中至少有两个键时进行归并排序
    {
        second_list = divide_from(the_list);
        recursive_merge_sort(the_list);
        recursive_merge_sort(second_list);
        combine(the_list, second_list);
    }
}

template <class Key>
Sortable_list<Key> Sortable_list<Key>::divide_from(Sortable_list<Key> &the_list)
/*Post: 将the_list分割成两个list其中第一个list较长保存再the_list中, 另一个
        返回为second_list.
  Uses:
*/
{
    int mid = (the_list.size()-1) / 2;  // 中间元素(若偶数个元素则为左中)的pos值
    int second_size = the_list.size() - (mid+1);
    Sortable_list<Key> second_list;

    for(int i = 0; i < second_size; i++)
    {
        Key data;
        the_list.remove(mid+1, data);    // 始终删除的是pos为mid+1的键
        second_list.insert(i, data);
    }
    return second_list;
}

template <class Key>
void Sortable_list<Key>::combine(Sortable_list<Key> &the_list,
                                 const Sortable_list<Key> &second_list)
/*Post: 将the_list和second_list中的键排序之后合并成新的list并返回.
  Uses:
*/
{
    Key data_the_list, data_second_list;
    Sortable_list<Key> temp_list;
    int pos_the_list = 0, pos_second_list = 0, pos_temp_list = 0;

    // the_list和second_list均非空时比较两者元素, 并按升序插入至temp_list
    while(pos_the_list < the_list.size() &&
          pos_second_list < second_list.size())
    {
        the_list.retrieve(pos_the_list, data_the_list);
        second_list.retrieve(pos_second_list, data_second_list);
        if(data_the_list <= data_second_list)
        {
            temp_list.insert(pos_temp_list, data_the_list);
            pos_the_list++;
        }
        else
        {
            temp_list.insert(pos_temp_list, data_second_list);
            pos_second_list++;
        }
        pos_temp_list++;
    }

    // 将仍有元素的表的剩余键按序插入temp_list
    while(pos_the_list < the_list.size())
    {
        the_list.retrieve(pos_the_list, data_the_list);
        temp_list.insert(pos_temp_list, data_the_list);
        pos_the_list++;
        pos_temp_list++;
    }
    while(pos_second_list < second_list.size())
    {
        second_list.retrieve(pos_second_list, data_second_list);
        temp_list.insert(pos_temp_list, data_second_list);
        pos_second_list++;
        pos_temp_list++;
    }
    the_list = temp_list;  // 操作符=重载将temp_list赋值给the_list返回
}



/**********************************
*            Quick Sort           *
**********************************/
template <class Key>
void Sortable_list<Key>::quick_sort()
/*Post:
  Uses:
*/
{
    recursive_quick_sort(*this);
}

template <class Key>
void Sortable_list<Key>::recursive_quick_sort(Sortable_list<Key> &the_list)
/*Post: 将the_list中的中间键作为pivot, 当the_list中的键的数目大于1时将其
        按与键pivot的相对大小分为the_list和second_list两个子表. 然后分别执行
        递归调用, 返回后将the_list, pivot, second_list进行合并.
  Uses:
*/
{
    // 中间元素(若偶数个元素则为左中)的pos值
    int pivot_position = (the_list.size()-1) / 2;
    Key pivot;
    the_list.remove(pivot_position, pivot);
    Sortable_list<Key> second_list;
    if(the_list.size() > 1)
    {
        second_list = partition(the_list, pivot);
        recursive_quick_sort(the_list);
        recursive_quick_sort(second_list);
        unite(the_list, second_list, pivot);
    }
    else if(the_list.size()==1)
    {
        Key data;
        the_list.retrieve(0, data);
        if(data<pivot)
            the_list.insert(1, pivot);
        else
            the_list.insert(0, pivot);
    }
    else
        the_list.insert(0, pivot);
}

template <class Key>
Sortable_list<Key> Sortable_list<Key>::partition(Sortable_list<Key> &the_list,
                                                 Key pivot)
/*Post: 将the_list中的键按与pivot的相对大小, 严格小于pivot的重新存入the_list,
        其他键存入second_list并返回, 且保持原来键的相对位置不变.
  Uses:
*/
{
    Sortable_list<Key> second_list, temp_list;
    int i, pos_temp_list = 0, pos_second_list = 0;
    Key data;
    for(i = 0; i < the_list.size(); i++)
    {
        the_list.retrieve(i, data);
        if(data < pivot)temp_list.insert(pos_temp_list++, data);
        else second_list.insert(pos_second_list++, data);
    }
    the_list = temp_list;
    return second_list;
}

template <class Key>
void Sortable_list<Key>::unite(Sortable_list<Key> &the_list,
                               Sortable_list<Key> &second_list,
                               Key pivot)
/*Post: 将pivot和second_list中的键依序插入至the_list的最末端.
  Uses:
*/
{
    int i;
    int pos_the_list = the_list.size();
    Key data;
    the_list.insert(pos_the_list++, pivot);     // 插入pivot至the_list末
    for(i = 0; i < second_list.size(); i++)
    {
        second_list.retrieve(i, data);
        the_list.insert(pos_the_list++, data);
    }
}



/********************************
*           Heap Sort           *
********************************/
template <class Key>
void Sortable_list<Key>::heap_sort()
/*Post: 先将顺序表构建成一个初始的大根堆, 再通过for循环, 每次将根元素移至未排序
        部分的尾部, 并重新将未排序部分重新排列为一个大根堆.
  Uses:
*/
{
    Key now;
    int last_unsorted;
    build_heap();  // 构建初始堆
    for(last_unsorted = Doubly_Linked_List<Key>::count-1;
        last_unsorted > 0; last_unsorted--)
    {
        now = entry[last_unsorted];
        // 将堆的根上的键移至最后, 即进行键排序
        entry[last_unsorted] = entry[0];
        insert_heap(now, 0, last_unsorted - 1);  // 重新排列堆
    }
}

template <class Key>
void Sortable_list<Key>::build_heap()
/*Post: 将顺序表建成一个初始堆.
  Uses:
*/
{
    int low;
    // count/2-1即最后一个结点的父亲结点索引, 自下而上, 自右向左构建大根堆
    for(low = Doubly_Linked_List<Key>::count/2-1; low >= 0; low--)
    {
        Key now = entry[low];
        // insert丢弃low位置元素, 将low位置now用作插入
        insert_heap(now, low, Doubly_Linked_List<Key>::count-1);
    }
}

template <class Key>
void Sortable_list<Key>::insert_heap(const Key &now, int low, int high)
/*Pre: 在索引low到high之间的键构成一个大根堆. 在索引low位置的键将被丢弃.
  Post: 键now将被插入至索引low到high之间, 并最终构成一个大根堆.
  Uses:
*/
{
    int large;
    large = 2*low+1;    // low的左孩子结点
    while(large <= high)
    {
        // 左孩子结点不是最后一个结点, 且左孩子结点小于右孩子结点
        if(large<high && entry[large]< entry[large+1])
            large++;
        // 已经是大根堆就跳出while循环
        if(now >= entry[large])
            break;
        else
        {
            entry[low] = entry[large];
            low = large;
            large = 2*low+1;
        }
    }
    entry[low] = now;
}

template <class Key>
void Sortable_list<Key>::insert_array(int position, const Key &data)
/*Post: 用作顺序实现堆排序.
  Uses:
*/
{
    Doubly_Linked_List<Key>::count++;
    Doubly_Linked_List<Key>::current_position = position;
    Doubly_Linked_List<Key>::set_position(position);

    entry[position] = data;
}

template <class Key>
void Sortable_list<Key>::traverse_array(void (*visit)(Key &))
/*Post: 对顺序表entry进行遍历, 并对其中的键执行visit的
  Uses:
*/
{
    int position;
    for(position = 0; position < Doubly_Linked_List<Key>::count;
        position++)  // 遍历列表的数组中所有元素并执行visit函数
        (*visit)(entry[position]);
}

#endif // SORTABLE_LIST_H

3. main.cpp
#include <iostream>
#include "Sortable_list.h"

using namespace std;

void print(Key &x)
{
    cout << x;
}

void test_insertion_sort()
/*Post: 进行插入排序的测试.
*/
{
    Sortable_list<Key> the_list;

    for(int i = 0; i < 10; i++)the_list.insert(i, Key(10-i));
    cout << "The list is:" << endl;
    the_list.traverse(print);

    cout << endl << "Use insertion_sort Method:" << endl;
    the_list.insertion_sort();
    the_list.traverse(print);
}

void test_selection_sort()
/*Post: 进行选择排序的测试.
*/
{
    Sortable_list<Key> the_list;

    for(int i = 0; i < 10; i++)the_list.insert(i, Key(10-i));
    cout << "The list is:" << endl;
    the_list.traverse(print);

    cout << endl << "Use selection_sort Method:" << endl;
    the_list.selection_sort();
    the_list.traverse(print);
}

void test_shell_sort()
/*Post: 进行希尔排序的测试.
*/
{
    Sortable_list<Key> the_list;

    for(int i = 0; i < 10; i++)the_list.insert_array(i, Key(10-i));
    cout << "The list is:" << endl;
    the_list.traverse_array(print);

    cout << endl << "Use shell_sort Method:" << endl;
    the_list.shell_sort();
    the_list.traverse_array(print);
}

void test_merge_sort()
/*Post: 进行归并排序的测试.
*/
{
    Sortable_list<Key> the_list;

    for(int i = 0; i < 10; i++)the_list.insert(i, Key(10-i));
    cout << "The list is:" << endl;
    the_list.traverse(print);

    cout << endl << "Use merge_sort Method:" << endl;
    the_list.merge_sort();
    the_list.traverse(print);
}

void test_quick_sort()
/*Post: 进行快速排序的测试.
*/
{
    Sortable_list<Key> the_list;

    for(int i = 0; i < 10; i++)the_list.insert(i, Key(10-i));
    cout << "The list is:" << endl;
    the_list.traverse(print);

    cout << endl << "Use quick_sort Method:" << endl;
    the_list.quick_sort();
    the_list.traverse(print);
}

void test_heap_sort()
/*Post: 进行堆排序的测试.
*/
{
    Sortable_list<Key> the_list;

    for(int i = 0; i < 10; i++)the_list.insert_array(i, Key(10-i));
    cout << "The list is:" << endl;
    the_list.traverse_array(print);

    cout << endl << "Use heap_sort Method:" << endl;
    the_list.heap_sort();
    the_list.traverse_array(print);
}

int main()
{
    //test_insertion_sort();
    //test_selection_sort();
    //test_shell_sort();
    //test_merge_sort();
    //test_quick_sort();
    //test_heap_sort();

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值