zoukankan      html  css  js  c++  java
  • 内部排序算法总结(一)

    内部排序算法总结(一)

    注:以下所有排序代码中都是通过简单的仿函数实现通用。该部分的代码实现是以下所有排序算法的基础

    //filename: stdafx.h
    #pragma once
    
    #include<iostream>
    using namespace std;
    
    #include<assert.h>
    template<class T>
    struct Great
    {
        bool operator()(const T&x, const T&y)
        {
            return x > y;
        }
    };
    
    template<class T>
    void PrintArr(T *arr, size_t n)
    {
        for (int i = 0; i < n; i++)
        {
            cout << arr[i] << " ";
        }
        cout << endl;
    }

    一.插入排序

    ①简单插入排序

      原理:对给定数组,遍历之并将之插入到已有的空组中(其实就是遍历点之前的已存有序组)

    //filename: InsertSort.h

     #pragma once
     #include"stdafx.h"

    template<class T,template <class>class Cmp = Great >
    void InsertSort(T *arr, size_t n)
    {
        assert(arr);
    
        ///1532685
        for (int beg = 1; beg < n; ++beg)
        {
            int end = beg - 1;
            while (end >= 0 && Cmp<T>()(arr[end], arr[end+1]))
            {
                swap(arr[end], arr[end + 1]);
                end--;
            }
        }
    }
    
    void TestInsertSort()
    {
        int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
        //ShellSort<int>(arr, 10);
    
        InsertSort<int>(arr, 10);
        PrintArr<int>(arr, 10);
    }

    ②希尔排序(缩小增量排序)

      原理:希尔排序是对插入排序的进一步优化提升。

      先将整个待排序序列分割成若干个子序列,分别进行直接插入排序,待整个序列中的数据“整体有序“时,再对整个序列进行一次 直接插入排序。

    //filename:InsertSort.h
    //希尔排序
    template<class T, template <class>class Cmp = Great >
    void ShellSort(T*arr, size_t n)
    {
        assert(arr);
        int gap = n;
        while (gap > 1)
        {
            gap = gap / 3 + 1;
            for (int beg = gap; beg < n; ++beg)
            {
                int end = beg-gap;
                while (end >= 0 && Cmp<T>()(arr[end], arr[end + gap]))
                {
                    swap(arr[end], arr[end + gap]);
                    end-=gap;
                }
            }
        }
    }
    
    void TestShellSort()
    {
        int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
        ShellSort<int>(arr, 10);
    
        //InsertSort<int>(arr, 10);
        PrintArr<int>(arr, 10);
    }

    二.选择排序

    ①直接选择排序

      原理:通过两层循环控制,外层确定次数为查找次数,内层找到当前最值放在最右或者左。

    //filename:SelectSort.h
    #include"stdafx.h" template<class T, template<class> class Cmp = Great> void SelectSort(T*arr, size_t n) { assert(arr); for (int beg = 0; beg < n; ++beg) { int flag = beg; for (int j = beg + 1; j < n; ++j) { if (Cmp<T>()(arr[flag], arr[j])) flag = j; } swap(arr[beg], arr[flag]); } } /////////////////////Test void TestSelectSort() { int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 }; //ShellSort<int>(arr, 10); SelectSort<int>(arr, 10); PrintArr<int>(arr, 10); }

    ②直接选择排序的优化

      改进:对于直接插入排序中的每次知道到最大/小值放在合适的位置这个点,进行加强:每次找到最大,最小值,放在两侧。从而减少交换次数

    //filename:SelectSort.h
    template<class T, template<class> class Cmp = Great>
    void BetSelectSort(T*arr, size_t n)
    {
        assert(arr);
    
        int beg = 0; 
        int end = n - 1;
        while(beg<end)
        {
            int leftF = beg;
            int rightF = end;
    
            for (int j = beg; j <=end; ++j)
            {
                if (Cmp<T>()(arr[leftF], arr[j]))
                    swap(arr[leftF], arr[j]);
                if (!Cmp<T>()(arr[rightF], arr[j]))
                    swap(arr[rightF], arr[j]);
            }
            ++beg; --end;
        }
    }
    //Test
    void TestBetSelectSort()
    {
        int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
        //ShellSort<int>(arr, 10);
    
        BetSelectSort<int>(arr, 10);
        PrintArr<int>(arr, 10);
    }

    ③堆排序

      原理:根据最大堆最小堆可以快速求得最值的策略。利用堆进行排序。取堆顶元素放在适当位置

    //filename:SelectSort.h 
    int
    Arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 }; template<class T, template<class> class Cmp = Great> void AdjustDown(T*arr, int n, int root) { if (n <=1) return; while (root <= (n - 2) / 2) { int child= root * 2 + 1; child = child + 1 < n ? Cmp<T>()(arr[child + 1], arr[child]) ? child + 1 : child : child; if (Cmp<T>()(arr[child], arr[root])) { swap(arr[child], arr[root]); } root = child; } } template<class T, template<class> class Cmp = Great> void heapSort(T*arr, size_t n) { //建堆 for (int i = (n - 2) / 2; i >= 0;--i) { AdjustDown(arr, n, i); } //排序 int end = n - 1; while (end > 0) { swap(arr[0], arr[end]); AdjustDown<T>(arr, end, 0); end--; } } void TestheapSort() { heapSort<int>(Arr, 10); PrintArr<int>(Arr, 10); }

    三.快速排序

    ①冒泡排序

      原理:通过N次遍历,每一次数据从头往后遍历,和相邻位置比较,如果顺序不正确就交换。直到全部有序

    //filename: FastSort.h
    #pragma once
    #include"stdafx.h"
    
    template<class T, template <class>class Cmp = Great >
    void BubbSort(T *arr, size_t n)
    {
        for (int beg = 0; beg < n; ++beg)
        {
            for (int j = 0; j < n - beg - 1; ++j)
            {
                if (Cmp<T>()(arr[j], arr[j + 1]))
                {
                    swap(arr[j], arr[j + 1]);
                }
            }
        }
    }
    void TestBubbSort()
    {
        int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
        BubbSort<int>(arr, 10);
        PrintArr<int>(arr, 10);
    }

    ②冒泡排序优化

      改进点:对冒泡排序,当某次冒泡的遍历过程中,发现遍历过程数据都是有序的,那么剩余的遍历冒泡就是非必要的。

    //filename:FastSort.h
    void
    BubbSort_B(T *arr, size_t n) { for (int beg = 0; beg < n; ++beg) { int flag = 0; for (int j = 0; j < n - beg - 1; ++j) { if (Cmp<T>()(arr[j], arr[j + 1])) { swap(arr[j], arr[j + 1]); //交换了那么设置调整开关为1 flag = 1; } } //如果遍历过程中不曾修改,那么说明序列有序,不在遍历 if (flag == 0) break; } }

    ③快速排序

      思想原理:通过一趟排序将待排序记录分割成独立的两部分,其一部分比另一部分关键字小,则可以对这两部分数据继续递归进行排序,直到有序

    template<class T, template <class>class Cmp = Great >
    void FastSort(T *arr, size_t n, int first, int last)
    {
        if (first < 0 || last >= n||first>last)
            return;
        int beg = first;
        int end = last;
        while (beg < end)
        {
            while (beg < end&&Cmp<T>()(arr[end], arr[beg]))
            {
                --end;
            }
            swap(arr[beg], arr[end]);
            while (beg < end && (Cmp<T>()(arr[end], arr[beg])))
            {
                ++beg;
            }
            swap(arr[beg], arr[end]);
        }
        //beg == end ==  中间元素
    
        FastSort(arr, n, first, beg - 1);
        FastSort(arr, n, beg + 1, last);
    }
    
    void TestFastSort()
    {
        int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
        FastSort<int>(Arr, 10,0,9);
        PrintArr<int>(Arr, 10);
    }

     四.归并排序

      归并:将两个或者两个以上的有序表组合成一个新的有序表

      2-路归并排序的核心操作:将一维数组中的相邻两个有序序列归并为一个有序序列

    // 归并排序中的合并算法
    void Merge(int array[], int start, int mid, int end)
    {
        int temp1[10], temp2[10];
        int n1, n2;
        n1 = mid - start + 1;
        n2 = end - mid;
        // 拷贝前半部分数组
        for (int i = 0; i < n1; i++)
        {
            temp1[i] = array[start + i];
        }
        // 拷贝后半部分数组
        for (int i = 0; i < n2; i++)
        {
            temp2[i] = array[mid + i + 1];
        }
        // 把后面的元素设置的很大
        temp1[n1] = temp2[n2] = 1000;
        // 逐个扫描两部分数组然后放到相应的位置去
        for (int k = start, i = 0, j = 0; k <= end; k++)
        {
            if (temp1[i] <= temp2[j])
            {
                array[k] = temp1[i];
                i++;
            }
            else
            {
                array[k] = temp2[j];
                j++;
            }
        }
    }
    // 归并排序
    void MergeSort(int array[], int start, int end)
    {
        if (start < end)
        {
            int i;
            i = (end + start) / 2;
            // 对前半部分进行排序
            MergeSort(array, start, i);
            // 对后半部分进行排序
            MergeSort(array, i + 1, end);
            // 合并前后两部分
            Merge(array, start, i, end);
        }
    }
    void TestMSort2()
    {
        int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
        MergeSort(arr, 0, 9);
        PrintArr<int>(arr, 10);
    }

    ②归并中的改进优化,对函数Merge进行改进,上边的方案中,只是静态的在栈上定义临时数组。大小固定。我们应当是用动态new来申请保存的

    而且,对于数组的临时保存,我们只需要保存头后者尾中的一半,然后反向归并即可。

    #include"stdafx.h"
    //[)[)
    template<class T,template<class>class Cmp = Great>
    void MerGe(int * arr, int start, int cir, int end)
    {
        assert(arr);
        int newLen = end - cir;
        int * newArr = new int[newLen];
        //保存后半部分值
        for (int i = cir; i < end; ++i)
        {
            newArr[i-cir] = arr[i];
        }
        //将后半部分并入元数组
        while (newLen&&cir)
        {
            //if (newArr[newLen - 1]>arr[cir - 1])
            if (Cmp<T>()(newArr[newLen - 1], arr[cir - 1]))
            {
                arr[--end] = newArr[newLen - 1];
                newLen--;
            }
            else
            {
                arr[--end] = arr[cir - 1];
                cir--;
            }
        }
        //如果后半部分有剩余,那么直接加入前半部分
        //否则就不处理,因为本身就是在原数组中处理的
        if (newLen)
        {
            for (int i = 0; i < newLen; ++i)
            {
                arr[i] = newArr[i];
            }
        }
        delete[]newArr;
    }
    // 归并排序
    template<class T,template<class> class Cmp = Great>
    void MergeSort(int array[], int start, int end)
    {
        if (start < end)
        {
            int i;
            i = (end + start) / 2;
            // 对前半部分进行排序
            MergeSort<T>(array, start, i);
            // 对后半部分进行排序
            MergeSort<T>(array, i + 1, end);
            // 合并前后两部分
            MerGe<T>(array, start, i, end);
        }
    }
    
    void TestMerge()
    {
            int arr[10] = { 1, 4, 7, 5, 2, 3, 6, 8, 9, 0 };
            MergeSort<int>(arr, 0, 10);
            PrintArr<int>(arr, 10);
    
    }
  • 相关阅读:
    RAID的详细配置
    RAID的基本介绍
    Linux的远程管理
    Linux防火墙iptables的基础
    【oacle入门】表空间类型
    【oracle入门】数据完整性约束
    【oracle入门】数据模型
    【Oracle入门】数据库的二级映像
    【oracle入门】数据库系统结构----三级模式
    【oracle入门】Oracle数据库11g企业版主要优点
  • 原文地址:https://www.cnblogs.com/lang5230/p/5354952.html
Copyright © 2011-2022 走看看