常见排序算法

Posted virgildevil

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常见排序算法相关的知识,希望对你有一定的参考价值。

常见排序算法

编写代码并测试了5种排序算法

有冒泡排序,选择排序,插入排序,堆排序,归并排序.

下面也给出了代码在机器上的运行结果,虽然不同机器结果会不一样,但是仍然能够比较直观地感受到这些算法的区别,以及理论与实现之间的差距.

// sort.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <vector>
#include <limits.h>
#include <time.h>
#include <string>
#include <stack>
#include <algorithm>

using namespace std;

//计时类,调用End将返回经历的秒数
class Timer {
private:
    clock_t start;
    clock_t finish;
    double duration;
public:
    Timer() {
        start = 0;
        finish = 0;
    };
    void Start() {
        start = clock();
    }
    double End() {
        finish = clock();
        duration = (double)(finish - start) / CLOCKS_PER_SEC;
        start = 0;
        finish = 0;
        return duration;
    }
};



//时间复杂度 平均O(n^2) 最坏(n^2) 最好O(n)
//空间复杂度 O(1)
//稳定性 稳定
namespace bubble_sort {
    void sort(vector<int>& v)
    {
        if (v.size() == 0)return;
        for (int j = 0; j < v.size(); j++)
        {
            for (int i = 0; i < v.size() - 1; i++)
            {
                if (v[i] > v[j])
                {
                    //swap(i,j)
                    int tmp = v[j];
                    v[j] = v[i];
                    v[i] = tmp;
                }
            }
        }


    }
}

//时间复杂度 平均O(n^2) 最坏(n^2) 最好O(n^2)
//空间复杂度 O(1)
//稳定性 不稳定
namespace select_sort {
    void sort(vector<int>& v)
    {
        if (v.size() == 0)return;
        for (int j = 0; j < v.size(); j++)
        {
            int min_pos = j;
            for (int i = j; i < v.size(); i++)
            {
                if (v[i] < v[min_pos]) {
                    min_pos = i;
                }
            }
            //swap(j,min_pos)
            int tmp = v[min_pos];
            v[min_pos] = v[j];
            v[j] = tmp;
        }
    }
}


//时间复杂度 平均O(n^2) 最坏(n^2) 最好O(n)
//空间复杂度 O(1)
//稳定性 稳定
namespace insert_sort {
    void sort(vector<int>& v)
    {
        if (v.size() == 0)return;
        for (int j = 1; j < v.size(); j++)
        {
            int i = j;
            while (i >= 1 && v[i] < v[i - 1])
            {
                //swap(i,i-1)
                int tmp = v[i - 1];
                v[i - 1] = v[i];
                v[i] = tmp;
                i--;
            }
        }
    }
}


namespace heap_sort_recur {

    struct Node {
        int val;
        Node* lchild;
        Node* rchild;
    };

    Node* head;
    int m_i = 0;
    vector<int> m_v;

    void re_build_heap(Node *node, Node *last_node, int val) {
        if (node == NULL) {
            Node* new_node = new Node;
            new_node->val = val;
            new_node->lchild = NULL;
            new_node->rchild = NULL;

            if (last_node->val > val) {
                last_node->lchild = new_node;
            }
            if (last_node->val <= val) {
                last_node->rchild = new_node;
            }
            return;
        }

        if (val < node->val)
        {
            re_build_heap(node->lchild, node, val);
        }
        if (val >= node->val)
        {
            re_build_heap(node->rchild, node, val);
        }

    }

    //中序遍历写回vector
    void re_write_back(Node* node)
    {
        if (node->lchild != NULL) {
            re_write_back(node->lchild);
        }
        if (node != NULL)
        {
            m_v[m_i] = node->val;
            m_i++;
        }
        if (node->rchild != NULL) {
            re_write_back(node->rchild);
        }
    }

    void sort(vector<int>& v)
    {
        if (v.size() == 0)return;
        m_v = v;
        head = new Node;
        head->lchild = NULL;
        head->rchild = NULL;
        head->val = m_v[0];
        for (int i = 1; i < m_v.size(); i++)
        {
            re_build_heap(head, head, m_v[i]);
        }
        re_write_back(head);
        for (int i = 0; i < v.size(); i++)
        {
            v[i] = m_v[i];
        }
    }
}

namespace heap_sort_arr {
    vector<int> arr;

    void sort(vector<int>& v)
    {
        /*Build Heap*/
        int k = 2;
        for (int i = 0; i < v.size(); i++)
        {
            k *= 2;
        }
        k--;

        arr.resize(k,-1);  // 存储树的数组,2^n - 1个元素 ,  -1  表示无数据
        arr[0] = v[0];
        for (int i = 1; i < v.size(); i++) {
            int j = 0;
            while (arr[j] != -1)
            {
                int left = 2 * j + 1;
                int right = 2 * j + 2;

                if (v[i] < arr[j]) {
                    j = left;
                }
                else {
                    j = right;
                }
            }
            arr[j] = v[i];
        }
        
        stack<int> s;
        int ii = 0;
        int now = 0;
        do {
            while (arr[now] != -1) {
                s.push(now);
                now = 2 * now + 1;
            }
            now = s.top();
            v[ii] = arr[now];
            s.pop();
            ii++;
            now = 2 * now + 2;
        } while (s.size() != 0 || arr[now] != -1);

        return;
    }

}

//时间复杂度 平均O(nlog2n) 最坏(nlog2n) 最好O(nlog2n)
//空间复杂度 O(1)
//稳定性 不稳定
namespace heap_sort_node {
    struct Node {
        int val;
        Node* lchild;
        Node* rchild;
    };

    //Test for print heap
    void recur_mid(Node* node) {
        if (node == NULL)return;
        recur_mid(node->lchild);
        cout << node->val << " ";
        recur_mid(node->rchild);

    }

    void sort(vector<int>& v)
    {
        /*Build Heap*/
        Node* head;
        head = new Node;
        head->val = v[0];
        head->lchild = NULL;
        head->rchild = NULL;

        Node* node;
        Node* last_node;
        for (int i = 1; i < v.size(); i++) {
            node = head;
            last_node = head;
            while (node != NULL)
            {
                if (v[i] < node->val) {
                    last_node = node;
                    node = node->lchild;
                }
                else {
                    last_node = node;
                    node = node->rchild;
                }
            }

            Node* new_node = new Node;
            new_node->val = v[i];
            new_node->lchild = NULL;
            new_node->rchild = NULL;

            if (v[i] < last_node->val) {
                last_node->lchild = new_node;
            }
            else {
                last_node->rchild = new_node;
            }

        }

        //Test for print heap
        //recur_mid(head);
        //cout << endl;

        //Use loop for inorder traversal to avoid stack overflow
        stack<Node*> s;
        int ii = 0;
        node = head;
        do {
            while (node != NULL) {
                s.push(node);
                node = node->lchild;
            }

            node = s.top();
            v[ii] = node->val;
            s.pop();
            ii++;
            node = node->rchild;
        } while (s.size() != 0 || node != NULL);

    }

}

//时间复杂度 平均O(nlog2n) 最坏(nlog2n) 最好O(nlog2n)
//空间复杂度 O(n)
//稳定性 稳定
namespace merge_sort {

    struct Interval {
        int left;
        int right;
        int state;  //记录着递归调用时的步骤
    };

    void sort(vector<int>& v)
    {
        int left = 0;
        int right = v.size() - 1;
        int mid = (right + left) / 2;

        Interval _inter;
        _inter.left = left;
        _inter.right = right;
        _inter.state = 0;

        //Convert recursion to loop
        /*
        recur(left,right)
        {
            if(left>=right)return;
            recur(left,mid);
            recur(mid+1,right);
            merge();
        }
        */

        stack<struct Interval> s;

        s.push(_inter);
        while (s.size() != 0)
        {
            Interval interval = s.top();
            s.pop();
            
            left = interval.left;
            right = interval.right;
            mid = (left + right) / 2;

            if (interval.state == 0) {
                if (left >= right) {
                    interval.state = 3;             //3  表示不处理这种情况
                    s.push(interval);
                    continue;
                }

                interval.state = 1;
                s.push(interval);

                Interval inter1;
                inter1.left = left;
                inter1.right = mid;
                inter1.state = 0;
                s.push(inter1);

            }
            else if (interval.state == 1) {
                interval.state = 2;
                s.push(interval);

                Interval inter1;
                inter1.left = mid+1;
                inter1.right = right;
                inter1.state = 0;
                s.push(inter1);
            }
            else if (interval.state == 2) {
                vector<int> vec; //Storage sorted data
                int i = left;
                int j = mid + 1;
                while (i <= mid || j <= right) {
                    //If one out of the limit, the other case is executed
                    if (j > right) {
                        vec.push_back(v[i]);
                        i++;
                        continue;
                    }
                    else if (i > mid) {
                        vec.push_back(v[j]);
                        j++;
                        continue;
                    }

                    //Keep the sort stable
                    if (v[i] <= v[j]) {
                        vec.push_back(v[i]);
                        i++;
                    }
                    else if (v[i] > v[j]) {
                        vec.push_back(v[j]);
                        j++;
                    }
                }

                //Copy sorted data to v
                for (int i = 0; i < vec.size(); i++)
                {
                    v[left + i] = vec[i];
                }

            }

        }

    }
}


enum DATA_TYPE {
    RANDOM,
    INC,
    DEC
};

class TestCase {
    Timer timer;
    vector<int> v;
    vector<int> ch_vec;
public:
    /*
    size:样例的个数
    dtype:生成样例的方式
    _sort:排序时调用的方法
    print_data:是否打印排序前数据和排序后数据
    check:是否进行错误检查
    */
    TestCase(int size, DATA_TYPE dtype, void(*_sort)(vector<int>&), bool print_data = false,bool check = false) {
        init_vec(size, dtype);
        
        //Sorting original data
        if (check) {
            ch_vec = v;
            std::sort(ch_vec.begin(), ch_vec.end());
        }

        //Unsorted data
        if (print_data) {
            print_vec();
        }

        //Sorting with provided method
        timer.Start();
        _sort(v);
        double duration = timer.End();
        cout << "cost time: " << duration << " seconds" << endl;
        
        //Sorted data
        if (print_data) {
            print_vec();
        }

        bool error = false;
        if (check) {
            for (int i = 0; i < v.size(); i++) {
                if (v[i] != ch_vec[i]) {
                    error = true;
                    break;
                }
            }
        }

        if (error) {
            cout << "incorrect result" << endl;
        }
        else {
            cout << "corret result" << endl;
        }

    }

    void print_vec()
    {
        if (v.size() == 0)return;
        for (int i = 0; i < v.size(); i++)
        {
            cout << v[i] << " ";
        }
        cout << endl;
    }
private:
    void init_vec(int size, DATA_TYPE dtype) {
        v.resize(size);
        switch (dtype) {
        case INC:
            for (int i = 0; i < size; i++)
            {
                v[i] = i;
            }
            break;
        case DEC:
            for (int i = 0; i < size; i++)
            {
                v[i] = size - i;
            }
            break;
        case RANDOM:
            srand(time(0));
            for (int i = 0; i < size; i++)
            {
                v[i] = rand()%9999;             //Make it smaller
                //v[i] = rand();                        

            }
            break;
        default:
            break;
        }
    }
};

int main() {
    const int SIZE = 30000;
    //TestCase testCase1(SIZE,RANDOM,bubble_sort::sort);                        //SIZE=2000,    3.4s
    //TestCase testCase2(SIZE,RANDOM,select_sort::sort);                        //SIZE=2000,    1.2s
    //TestCase testCase3(SIZE,RANDOM,insert_sort::sort);                        //SIZE=2000,    1.3s
    //TestCase testCase4(SIZE, RANDOM, heap_sort_recur::sort);                  //SIZE=80000,   0.2s  然而SIZE = 100000的时候,malloc failure: Stack overflow    
    //TestCase testCase5(SIZE, RANDOM, heap_sort_arr::sort);                    //SIZE=23,      2.0s  由于使用数组存储树,空间利用率低下,特别是当树结构恶化的时候vector将无法申请到足够的内存
    //TestCase testCase6(SIZE, RANDOM, heap_sort_node::sort,false,true);        //SIZE=100000,  1.0s  最快的一个
    //TestCase testCase7(SIZE, RANDOM, merge_sort::sort, false, true);          //SIZE=30000,   2.0S  时间主要花在了临时数据的拷贝,存储和释放上面

    return 0;
}

以上是关于常见排序算法的主要内容,如果未能解决你的问题,请参考以下文章

基于比较的七种常见排序算法

基于比较的七种常见排序算法

算法 | Java 常见排序算法(纯代码)

常见排序算法

常见排序算法思路和简单代码实现

常见排序算法代码总结(Java版)