C++语言实现一些基本算法(两点距离、点是否在直线上、点与直线的关系、两直线的夹角、两直线的交点、两个举行的重合面积等等)

工程源码下载地址:https://download.csdn.net/download/cwj066/10667645

struct QUICKSORT
{
    int iIndex;
    float fAngle;

    QUICKSORT(int iIndex, float fAngle)
    {
        this->iIndex = iIndex;
        this->fAngle = fAngle;
    }
    QUICKSORT() {memset(this, 0, sizeof(*this));}
};

//定义点结构体
struct myPoint
{
    int x; //点的x坐标
    int y; //点的y坐标

    myPoint(){memset(this, 0, sizeof(*this));}
    myPoint(int x, int y)
    {
        this->x = x;
        this->y = y;
    }

    bool operator==(const myPoint &other) const
    {
        return (this->x == other.x && this->y == other.y);
    }
};

1:求两点的的距离

/********************************************************************
 * 函数名称 : segmentLength
 * 函数功能 : 求两点的长度(勾股定理)
 * 输入参数1: pt1 第一个点
 * 输入参数2: pt2 第二个点
 * 输出参数: 无
 * 返回参数: pt1到pt2的距离
 * 日   期: 2018年09月13日
 * 作   者: mark-plus
********************************************************************/
float segmentLength(const myPoint &pt1, const myPoint &pt2)
{
    float x = fabs(pt1.x - pt2.x);
    float y = fabs(pt1.y - pt2.y);
    float fLength = sqrt((x * x + y * y));

    return fLength;
}

2:判断点是否在直线上

/********************************************************************
 * 函数名称 : pointOnSegment
 * 函数功能 : 判断点是否在线段上
 * 输入参数1: pt1 线段的第一个点
 * 输入参数2: pt2 线段的第二个点
 * 输入参数3: ptNode 需要判断的点
 * 输出参数: 无
 * 返回参数: true:点ptNode在线段上 false:点ptNode在在线段上
 * 日   期: 2018年09月13日
 * 作   者: mark-plus
********************************************************************/
bool pointOnSegment(const myPoint &pt1, const myPoint &pt2, const myPoint &ptNode)
{
    float a = segmentLength(pt1, pt2);
    float b= segmentLength(pt1, ptNode);
    float c= segmentLength(pt2, ptNode);

    if (a == (b +c)) return true;
    else return false;
}

3:判断点是否在直线外

/********************************************************************
 * 函数名称 : pointOnSegmentOutSide
 * 函数功能 : 判断某个点是否在线段外
 * 输入参数1: pt1 线段的第一个点
 * 输入参数2: pt2 线段的第二个点
 * 输入参数3: ptNode 需要判断的点
 * 输出参数: 无
 * 返回参数: true:点ptNode在线外 false:点ptNode在线上
 * 日   期: 2018年09月13日
 * 作   者: mark-plus
********************************************************************/
bool pointOnSegmentOutSide(const myPoint pt1, const myPoint pt2, const myPoint ptNode)
{
    float a = segmentLength(pt1, pt2);
    float b= segmentLength(pt1, ptNode);
    float c= segmentLength(pt2, ptNode);

    if (b > a || c > a) return false;
    else return true;
}

4:求两直线的交点

/********************************************************************
 * 函数名称 : intersect
 * 函数功能 : 求两直线的交点(参考了Qt里面两直线求交点的算法)
 * 输入参数1: pt1 直线1的第1个点
 * 输入参数2: pt2 直线1的第2点
 * 输入参数3: pt3 直线2的第1个点
 * 输入参数4: pt4 直线2的第2个点
 * 输出参数: ptNode 直线1和直线2的交点
 * 返回参数: true:直线1和直线2有交点 false:true:直线1和直线2没有交点
 * 日   期: 2018年09月13日
 * 作   者: mark-plus
********************************************************************/
bool intersect(const myPoint &pt1, const myPoint &pt2, const myPoint &pt3, const myPoint &pt4, myPoint &ptNode)
{
    myPoint a(pt2.x - pt1.x, pt2.y - pt1.y);
    myPoint b(pt3.x - pt4.x, pt3.y - pt4.y);
    myPoint c(pt1.x - pt3.x, pt1.y - pt3.y);

    float fDenominator = a.y * b.x - a.x * b.y;
    if (fDenominator == 0) return false;

    float fReciprocal = 1 / fDenominator;
    float na = (b.y * c.x - b.x * c.y) * fReciprocal;
    ptNode = myPoint(a.x * na + pt1.x, a.y * na + pt1.y);

    if (na < 0 || na > 1) return true;

    float nb = (a.x * c.y - a.y * c.x) * fReciprocal;
    if (nb < 0 || nb > 1) return true;

    return true;
}

5:求三角形面积

/********************************************************************
 * 函数名称 : triangleArea
 * 函数功能 : 三点求三角形的面积(海伦公式)
 * 输入参数1: pt1 三角形的第1个点
 * 输入参数2: pt2 三角形的第2个点
 * 输入参数3: pt3 三角形的第3个点
 * 输出参数: 无
 * 返回参数:三角形的面积
 * 日   期: 2018年09月13日
 * 作   者: mark-plus
********************************************************************/
float triangleArea(const myPoint &pt1, const myPoint &pt2, const myPoint &pt3)
{
    float a = segmentLength(pt1, pt2);//三角形的a边
    float b = segmentLength(pt2, pt3);//三角形的b边
    float c = segmentLength(pt3, pt1);//三角形的c边

    float p = (a + b + c) / 2;//三角形的周长一半
    float fArea = sqrt((p * (p - a) * (p - b) * (p - c)));//用海伦公式计算三角形面积

    return fArea;
}

6:判断点与矩形的关系

// 功能:判断点与矩形的关系(const vector<myPoint> vPointF, const myPoint &pt)
// 方法:求解通过该点的水平线与多边形各边的交点
// 结论:单边交点为奇数,成立!
//参数:
// myPoint pt 指定的某个点
// vector<myPoint> vPointF多边形的各个顶点坐标(首末点可以不一致)
/********************************************************************
 * 函数名称 : containsPointPolygon
 * 函数功能 : 判断点(pt)是否在多边形内(vPointF)
 * 输入参数1: vPointF 矩形的四个顶点,顶点要顺序放置(A-B-C-D-A)
 * 输入参数2: pt 需要判断的点
 * 输出参数 : 无
 * 返回参数 : 0:在多边形外 1:在多变形内 2:在多变形的边上
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
int containsPointPolygon(const vector<myPoint> &vPointF, const myPoint &pt)
{
    if (vPointF.size() == 0) return 0;

    int nCross = 0;
    int nCount = vPointF.size();
    for (int i = 0; i < nCount; i++)
    {
        myPoint p1 = vPointF[i];
        myPoint p2 = vPointF[(i + 1) % nCount];

        if (pointOnSegment(p1, p2, pt)) return 2; //相交点刚好在边上

        // 求解 y=p.y 与 p1p2 的交点
        if (p1.y == p2.y) continue; //p1p2 与 y=p0.y平行

        if (pt.y < min(p1.y, p2.y)) continue; //交点在p1p2延长线上

        if (pt.y >= max(p1.y, p2.y)) continue; //交点在p1p2延长线上

        // 求交点的x坐标
        float x = ((pt.y - p1.y) * (p2.x - p1.x)) / (p2.y - p1.y) + p1.x;
        if (x > pt.x) nCross++; // 只统计单边交点
    }

    // 单边交点为偶数,点在多边形之外 ---
    return ((nCross & 1) == 1);
}

7:判断点在直线的那一侧

/********************************************************************
 * 函数名称 : pointLineRelationship
 * 函数功能 : 判断点与直线的关系
 * 输入参数1: pt1 直线的第1个点
 * 输入参数2: pt2 直线的第2个点
 * 输入参数3: ptNode 需要判断的点
 * 输出参数 : 无
 * 返回参数 : 0:点在直线上 大于0:点在直线Pt3顺时针那侧 小于:0,点在直线Pt3逆时针那侧,
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
int pointLineRelationship(const myPoint &pt1, const myPoint &pt2, myPoint &ptNode)
{
    //iValue=0,点在分割线上,iValue>0,点在直线Pt3顺时针那侧,iValue<0,点在直线Pt3逆时针那侧,
    int iRet = ((pt2.y - pt1.y) * ptNode.x + (pt1.x-pt2.x) * ptNode.y + (pt2.x*pt1.y - pt1.x*pt2.y));

    return iRet;
}

8:求两直线的夹角

/********************************************************************
 * 函数名称 : line2LineAnge
 * 函数功能 : 求两直线的夹角(小于90)
 * 输入参数1: pt1 直线1的第1个点
 * 输入参数2: pt2 直线1的第2个点
 * 输入参数3: pt3 直线2的第1个点
 * 输入参数4: pt4 直线3的第2个点
 * 输出参数 : 无
 * 返回参数 : 直线1和直线2的夹角
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
float line2LineAnge(const myPoint &pt1, const myPoint &pt2, const myPoint &pt3, const myPoint &pt4)
{
    //            /|
    //         z / | y
    //          /θ |
    //         /----
    //           x
    //利用cosθ = x/z求角度
    float v1 = pt2.x - pt1.x;
    float v2 = pt2.y - pt1.y;
    float v3 = pt4.x - pt3.x;
    float v4 = pt4.y - pt3.y;
    float fAngle0 = (v1*v3+v2*v4)/((sqrt(v1*v1+v2*v2))*(sqrt(v3*v3+v4*v4)));
    float fAngle1 = acos(fAngle0);

    float fAngle2 = 0;
    if(fAngle1 * (180.0  / PI) >= 90) fAngle2 = 180 - (fAngle1 * (180.0 / PI));
    else fAngle2 = fAngle1 *(180.0 / PI);

    return fAngle2;
}

/********************************************************************
 * 函数名称 : containsPointVector
 * 函数功能 : 查找vector容器里面的没有重复的元素(myPoint重载了==运算符)
 * 输入参数1: vPointF 被判断的所有元素
 * 输入参数2: pt 需要判断的点
 * 输出参数 : 无
 * 返回参数 : true:不在容器里 false:在容器里
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
bool containsPointVector(const vector<myPoint> vPointF, const myPoint &pt)
{
    int iSize = vPointF.size();
    if (iSize <= 0) return true;

    for (int i = 0; i < iSize; i++)
    {
        if (vPointF[i] == pt) return false;
    }

    return true;
}

/********************************************************************
 * 函数名称 : quickSort
 * 函数功能 : 快速排序
 * 输入参数1: vData 需要快速排序的数据
 * 输入参数2: iStart 第1个元素的下标
 * 输入参数3: iEnd 第2个元素的下标
 * 输出参数 : vData排序好的数据(从大到小排序) 注释:如果需要从小到大排序,把 > 改为 <,把 < 改为 >
 * 返回参数 : 无
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void quickSort(vector<QUICKSORT> &result, const int iStart, const int iEnd)
{
    if(iEnd <= iStart) return; //到了长度小于1这种情况已经是有序列了

    //数组result,first是第一个元素下标,last是最后一个元素下标
    QUICKSORT mKey = result[iStart];
    int iLeft = iStart + 1;//left等于第二个元素
    int iRight = iEnd;

    while(iLeft <= iRight)
    {
        while(result[iRight].fAngle < mKey.fAngle && iRight >= iLeft)//找到一个比first小的,但必须保证left值小于等于right值
        {
            iRight--;
        }

        while(result[iLeft].fAngle > mKey.fAngle && iLeft <= iRight) //找到一个比first大的,但得保证left值小于等于right值
        {
            iLeft++;
        }

        if(iLeft >= iRight) break; //说明已经是相对有序序列,无需交换

        QUICKSORT mTemp = result[iLeft];//交换位置
        result[iLeft] = result[iRight];
        result[iRight] = mTemp;
        iLeft++;
        iRight--;//相应的进一位
    }
    result[iStart] = result[iRight];//因为right一定是停在从右到左第一个小于first的数上,交换之后,
    //依然能保证first值左边的比first小,右边的比first大

    result[iRight] = mKey;
    quickSort(result, iStart, iRight-1);//左半部分
    quickSort(result, iLeft, iEnd);//右半部分
}

/********************************************************************
 * 函数名称 : clockWiseSortPoints
 * 函数功能 : 对多边形无序的顶点进行 按顺时针排序
             因为我的多边顶点是两个相同矩形的相交点,所以是一个凸多边形
             所以可以用所有顶点的重心与每个顶点求角度,按角度从大到小排序
             就可以把无序的顶点按顺时针排序(此方法只适合凸多边形)
 * 输入参数1: vPoint 需要排序的图多变形的点
 * 输出参数 : vPoint 按顺时针排序好的凸多边形的点
 * 返回参数 : 无
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void clockWiseSortPoints(vector<myPoint> &vPoint)
{
    if (vPoint.size() <= 0) return;

    //1 计算所有定点的重心
    float fSumX = 0, fSumY = 0;
    int iSize = vPoint.size();
    for (int i = 0; i < iSize; i++)
    {
        fSumX += vPoint[i].x;
        fSumY += vPoint[i].y;
    }
    myPoint ptCenter = myPoint(fSumX / iSize, fSumY / iSize);

    //2 计算每个顶点与重心的斜率(角度)
    vector<QUICKSORT> vAngle;
    for (int i = 0; i < iSize; i++)
    {
        float x = vPoint[i].x - ptCenter.x;
        float y = vPoint[i].y - ptCenter.y;
        float v = atan2(y, x) ;//反三角计算角度(c语言出来的是弧度)
        float fAngle = (v * 180) / PI;//转为角度(0 - 360)

        vAngle.push_back(QUICKSORT(i, fAngle));
    }

    //3 对角度从大到小排序
    quickSort(vAngle, 0, iSize - 1);

    //4 按角度顺序排序多边形的顶点
    vector<myPoint> vPointNew;
    for (int i = 0; i < iSize; i++)
    {
        vPointNew.push_back(vPoint[vAngle[i].iIndex]);
    }

    vPoint = vPointNew;
}

9:求两个矩形的重合面积

/********************************************************************
 * 函数名称 : rect2RectArea
 * 函数功能 : 求两个矩形的重合面积
 * 输入参数1: vRectF1 第1个矩形的四个顶点
 * 输入参数2: vRectF2 第2个矩形的四个顶点
 * 输出参数 : 无
 * 返回参数 : 矩形1和矩形2从何面积
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
float rect2RectArea(const vector<myPoint> vRectF1, const vector<myPoint> vRectF2)
{
    //1、原数据合法性判断
    if (vRectF1.size() == 0 || vRectF2.size() == 0 || vRectF1.size() != vRectF2.size()) return 0;

    //2 判断一个矩形的某个顶点是否在另外一个矩形内部,保存在矩形内部的点
    vector<myPoint> vPontF3;
    int iSize = vRectF1.size();
    for (int i = 0; i < iSize; i++)
    {
        if (containsPointPolygon(vRectF1, vRectF2[i]) && containsPointVector(vPontF3, vRectF2[i])) vPontF3.push_back(vRectF2[i]);
        if (containsPointPolygon(vRectF2, vRectF1[i]) && containsPointVector(vPontF3, vRectF1[i])) vPontF3.push_back(vRectF1[i]);
    }

    //3 保存两个矩形边相交的所有交点
    for (int i = 0; i < iSize; i++)
    {
        for (int j = 0; j < iSize; j++)
        {
            //3.1 计算两直线的交点
            myPoint ptNode(-9999, -9999);
            bool bRet1 = intersect(vRectF1[i], vRectF1[(i == iSize - 1) ? 0 : i + 1], vRectF2[j],
                    vRectF2[(j == iSize - 1) ? 0 : j + 1], ptNode);
            if (!bRet1) continue; //没有交点

            //3.2 判断交点是否在相交的两条直线上
            bool bRet2 = pointOnSegmentOutSide(vRectF1[i], vRectF1[(i == iSize - 1) ? 0 : i + 1], ptNode);
            bool bRet3 = pointOnSegmentOutSide(vRectF2[j], vRectF2[(j == iSize - 1) ? 0 : j + 1], ptNode);

            //3.3 保存符合条件的相交点
            if (bRet2 == true  && bRet3 == true && containsPointVector(vPontF3, ptNode)) vPontF3.push_back(ptNode);
        }
    }

    iSize = vPontF3.size();
    if (iSize < 3) return 0; //少于三个点不用计算面积

    //4、先对多边形的点按顺时针排序(等于3个点,这些点就是有序的,不需要排序)
    if (iSize > 3) clockWiseSortPoints(vPontF3);

    //5、计算两个矩形重合的面积
    float fAreaPolygon = 0;
    for (int i = 2; i < iSize; i++)
    {
        fAreaPolygon += triangleArea(vPontF3[0], vPontF3[i - 1], vPontF3[i]);
    }

    return fAreaPolygon;
}

10:冒泡排序(Bubble Sort)

冒泡排序描述:冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 

冒泡排序算法步骤:

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

/********************************************************************
 * 函数名称 : bubbleSort
 * 函数功能 : 冒泡排序
 * 输入参数1: vData 需要快速排序的数据
 * 输出参数 : 无
 * 返回参数 : vData 排序好的数据
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void bubbleSort(vector<int> &vData)
{
    //1、原数据合法性判断
    if (vData.size() == 0) return;

    int iSize = vData.size();
    for (int i = 0; i < iSize; i++)
    {
        for (int j = i+1; j < iSize; j++)
        {
            int iTem = vData[i];
            if (iTem > vData[j])
            {
                vData[i] = vData[j];
                vData[j] = iTem;
            }
        }
    }
}

11:选择排序(Selection Sort)

选择排序描述:选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

冒泡排序算法步骤:

n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  • 初始状态:无序区为R[1..n],有序区为空;
  • 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  • n-1趟结束,数组有序化了。

/********************************************************************
 * 函数名称 : selectSort
 * 函数功能 : 选择排序
 * 输入参数1: vData 需要选择排序的数据
 * 输出参数 : 无
 * 返回参数 : vData 排序好的数据
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void selectSort(vector<int> &vData)
{
    //1、原数据合法性判断
    if (vData.size() == 0) return;

    int iIndex = 0;

    int iSize = vData.size();
    for (int i = 0; i < iSize - 1; i++)
    {
        iIndex = i;
        for (int j = i+1; j < iSize; j++)
        {
            if (vData[j] < vData[iIndex])
            {
                iIndex = j;
            }
        }

        int iTemp = vData[i];
        vData[i] = vData[iIndex];
        vData[iIndex] = iTemp;
    }
}

12:选择排序(Selection Sort)

插入排序描述:插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

选择排序算法步骤:

一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

  • 从第一个元素开始,该元素可以认为已经被排序;
  • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  • 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  • 将新元素插入到该位置后;
  • 重复步骤2~5。

/********************************************************************
 * 函数名称 : inserSort
 * 函数功能 : 插入排序
 * 输入参数1: vData 需要插入排序的数据
 * 输出参数 : 无
 * 返回参数 : vData 排序好的数据
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void inserSort(vector<int> &vData)
{
    //1、原数据合法性判断
    if (vData.size() == 0) return;

    int iPreIndex = 0;
    int iCurrent = 0;
    int iSize = vData.size();
    for (int i = 1; i < iSize; i++)
    {
        iPreIndex = i - 1;
        iCurrent = vData[i];
        while (iPreIndex >= 0 && vData[iPreIndex] > iCurrent)
        {
            vData[iPreIndex + 1] = vData[iPreIndex];
            iPreIndex--;
        }

        vData[iPreIndex + 1] = iCurrent;
    }
}

13:希尔排序(Shell Sort)

希尔排序描述:1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序

希尔排序算法步骤:

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

  • 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  • 按增量序列个数k,对序列进行k 趟排序;
  • 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

/********************************************************************
 * 函数名称 : shellSort
 * 函数功能 : 希尔排序
 * 输入参数1: vData 需要希尔排序的数据
 * 输出参数 : 无
 * 返回参数 : vData 排序好的数据
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void shellSort(vector<int> &vData)
{
    //1、原数据合法性判断
    if (vData.size() == 0) return;

    int iPreIndex = 0;
    int iCurrent = 0;
    int iSize = vData.size();
    int iIncrement = iSize;
    while (iIncrement > 1)
    {
        iIncrement = iIncrement / 3 + 1;
        for (int i = iIncrement; i < iSize; i++)
        {
            iPreIndex = i - 1;
            iCurrent = vData[i];
            while (iPreIndex >= 0 && vData[iPreIndex] > iCurrent)
            {
                vData[iPreIndex + 1] = vData[iPreIndex];
                iPreIndex--;
            }

            vData[iPreIndex + 1] = iCurrent;
        }
    }
}

14:合并排序(Merge Sort)

归并排序描述:归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。 

归并排序算法步骤:

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

/********************************************************************
 * 函数名称 : mergeSort
 * 函数功能 : 合并排序
 * 输入参数1: vData 需要合并排序的数据
 * 输出参数 : 无
 * 返回参数 : vData 排序好的数据
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void mergeSort(vector<int> &vData, int iLeft, int iRight, vector<int> &vRetData)
{
    //1、完成排序 退出递归
    if(iLeft >= iRight) return;

    int iMid = iLeft + ((iRight - iLeft) / 2);
    mergeSort(vData, iLeft, iMid, vRetData); //递归左半数组
    mergeSort(vData, iMid+1, iRight, vRetData); //递归右半数组

    //2、将排好序的左右两部分数组归并
    int iStart1 = iLeft;
    int iStop1 = iMid;
    int iStart2 = iMid + 1;
    int iStop2 = iRight;
    int iIndex = iLeft;

    //3、循环条件:任一个数组排序完,则终止条件,最后将没有比较完的数组直接一一拷过去
    while( iStart1 <= iStop1 && iStart2 <= iStop2 )
    {
        if( vData[iStart1] <= vData[iStart2] )
        {
            vRetData[iIndex++] = vData[iStart1++];
        }
        else
        {
            vRetData[iIndex++] = vData[iStart2++];
        }
    }

    //4、右半数组走完了
    while( iStart1 <= iStop1 )
    {
        vRetData[iIndex++] = vData[iStart1++];
    }

    //5、左半数组走完了
    while( iStart2 <= iStop2 )
    {
        vRetData[iIndex++] = vData[iStart2++];
    }

    //6、vRetDatap数组已经排好序,将数组内容拷到原数组,递归向上一层走
    iIndex = iLeft;
    while( iIndex <= iRight )
    {
        vData[iIndex] = vRetData[iIndex];
        ++iIndex;
    }
}

15:合并排序(Quick Sort)

快速排序描述:快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

快速排序算法步骤:

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

/********************************************************************
 * 函数名称 : quickSort
 * 函数功能 : 快速排序
 * 输入参数1: vData 需要快速排序的数据
 * 输入参数2: iStart 第1个元素的下标
 * 输入参数3: iEnd 第2个元素的下标
 * 输出参数 : vData排序好的数据(从大到小排序) 注释:如果需要从小到大排序,把 > 改为 <,把 < 改为 >
 * 返回参数 : 无
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void quickSort(vector<int> &result, const int iStart, const int iEnd)
{
    if(iEnd <= iStart) return; //到了长度小于1这种情况已经是有序列了

    //数组result,first是第一个元素下标,last是最后一个元素下标
    int mKey = result[iStart];
    int iLeft = iStart + 1;//left等于第二个元素
    int iRight = iEnd;

    while(iLeft <= iRight)
    {
        while(result[iRight] > mKey && iRight >= iLeft)//找到一个比first小的,但必须保证left值小于等于right值
        {
            iRight--;
        }

        while(result[iLeft] < mKey && iLeft <= iRight) //找到一个比first大的,但得保证left值小于等于right值
        {
            iLeft++;
        }

        if(iLeft >= iRight) break; //说明已经是相对有序序列,无需交换

        int mTemp = result[iLeft];//交换位置
        result[iLeft] = result[iRight];
        result[iRight] = mTemp;
        iLeft++;
        iRight--;//相应的进一位
    }
    result[iStart] = result[iRight];//因为right一定是停在从右到左第一个小于first的数上,交换之后,
    //依然能保证first值左边的比first小,右边的比first大

    result[iRight] = mKey;
    quickSort(result, iStart, iRight-1);//左半部分
    quickSort(result, iLeft, iEnd);//右半部分
}

16:计数排序(count Sort)

快速排序描述:计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

快速排序算法步骤:

  • 找出待排序的数组中最大和最小的元素;
  • 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

/********************************************************************
 * 函数名称 : countSort
 * 函数功能 : 计数排序
 * 输入参数1: vData 需要计数排序的数据
 * 输出参数 : 无
 * 返回参数 : vData 排序好的数据
 * 日   期 : 2018年09月13日
 * 作   者 : mark-plus
********************************************************************/
void countSort(vector<int> &vData)
{
    //1、原数据合法性判断
    if (vData.size() == 0) return;

    //2、找出vData最大的值
    int iMax = vData[0];
    int iSize = vData.size();
    for (int i = 1; i < iSize; i++)
    {
        if (iMax < vData[i]) iMax = vData[i];
    }

    //3、创建一个长度为iMax的数组
    int *iCount = new int[iMax + 1];
    memset(iCount, 0, sizeof(int) * (iMax + 1));
    for (int i = 0; i < iSize; i++)
    {
        iCount[vData[i]]++; //计数
    }

    //4、取出数据就是有序的
    vData.clear();
    for (int i = 0; i < (iMax + 1); i++)
    {
        if (iCount[i] != 0)
        {
            for (int j = 0; j < iCount[i]; j++) vData.push_back(i);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/cwj066/article/details/82692271