内部排序算法总结(一)

内部排序算法总结(一)

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

//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);

}

 

posted @ 2016-04-06 10:28  狼行博客园  阅读(1247)  评论(0编辑  收藏  举报