各类算法实现(sort)

来源:互联网 发布:敷面膜知乎 编辑:程序博客网 时间:2024/06/06 01:27
#ifndef __INSERTSORT_H__#define __INSERTSORT_H__#include "QuickSort.h"#include <stdio.h>/*#######################################################################################插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序)因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。步骤:从第一个元素开始,该元素可以认为已经被排序取出下一个元素,在已经排序的元素序列中从后向前扫描如果该元素(已排序)大于新元素,将该元素移到下一位置重复步骤3,直到找到已排序的元素小于或者等于新元素的位置将新元素插入到该位置中重复步骤2########################################################################################*///将数组分为两侧,一侧有序,另一侧无序,每次从无序数组中选取一个数字,插入到有序数组的相应位置,使其有序void InsertSort(int arr[], int left, int right)//直接插入排序,拿到这个数,                                            //与前面已排好的数比较,直到temp大于已排好的一个数在成块后移,插入{    int temp;    int j = 0;//后一个与前一个已排好的序列比较    for (int i = 1; i <= right; i++)    {        temp = arr[i];        for (j = i; j >=0 && arr[j - 1] > temp; j--)            arr[j] = arr[j - 1];//成块后移        arr[j] = temp;//把temp排好    }}/*#########################################################希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。希尔排序是基于插入排序的以下两点性质而提出改进方法的:1、插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率2、但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位>#########################################################*///void ShallinsertSort(int arr[],int right)//希尔排序{ int len = right+1; if(len<=1||arr==NULL)  return; for(int div=len/2;div>=1;div=div/2)//定增量div,并不断减小 {  for(int i=0;i<=div;++i)//分组成div组  {   for(int j=i;j<len-div;j+=div)//对每组进行插入排序    for(int k=j;k<len;k+=div)     if(arr[j]>arr[k])      Swap(arr[j],arr[k]);//交换两个数的值  } }}#endifShell排序的时间性能优于直接插入排序希尔排序的时间性能优于直接插入排序的原因:①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。②当n值较小时,n和  的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(  )差别不大。③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。因此,希尔排序在效率上较直接插入排序有较大的改进。//#######################################################//冒泡排序#ifndef __BUBBLESORT_H__#define __BUBBLESORT_H__#include "QuickSort.h"#include <stdio.h>//不停地交换比较arr[i]与arr[i+1]   使最大值下沉void BubbleSort1(int arr[], int left, int right){    if (arr == NULL || left <0 || left> right)        return;    for (int i = 1; i <= right; i++)//正向检测    {        for (int j = 0; j <= right - i - 1; j++)        {            if (arr[j] >= arr[j + 1])            {                Swap(arr[j], arr[j + 1]);            }        }    }}void BubbleSort2(int arr[], int left, int right) //反向检测{    //bool exchange;    if (arr == NULL || left <0 || left> right)        return;    for (int i = 0; i < right; i++)    {        //exchange = 0;        for (int j = right; j >=i+1 ; j--)        {            if (arr[j] <= arr[j-1])            {                Swap(arr[j], arr[j -1]);                //exchange = 1;            }            //if (exchange == 0)            //  return;        }    }}#endif//#######################################################ifndef __QUICKSORT_H__#define __QUICKSORT_H__#include <stdio.h>#include <stdlib.h>//将数组分为两部分,left全是小于key,right全是大于key,再递归将小数组在子问题void Swap(int& a, int&b){    int temp = a;    a = b;    b = temp;}/*################################################################快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。步骤:从数列中挑出一个元素,称为 “基准”(pivot),重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序########################################################################################*/int Partition1(int arr[], int left, int right){    //左右指针法    if (arr == NULL || left <0 || left>right)        return -1;    int begin = left;    int end = right;    int key = arr[right];    while (begin < end)    {        while (arr[begin] <= key && begin <end)// begin从左 找大数,end从右找小数,然后交换        begin++;        while (arr[end]>=key && begin < end)            end--;        Swap(arr[begin], arr[end]);    }        Swap(arr[begin], arr[right]);//最后begin与 key 值交换 使key左边得值小于key,key右边的值大于key    return begin;}int Partition2(int arr[], int left, int right){    //挖坑法    //保存key值    //利用两个指针,begin先走,找大,填到右边,end再走,找小,填到左边    if (arr == NULL || left<0 || left> right)        return -1;    int begin = left;    int end = right;    int key = arr[right];    while (begin < end)    {        while (arr[begin] <= key && begin<end)            begin++;        arr[end] = arr[begin];        while (arr[end] >= key && begin < end)            end--;        arr[begin] = arr[end];    }    arr[begin] = key;    return begin;}int Partition3(int arr[], int left, int right){    //前后指针法    //    if (arr == NULL || left<0 || left> right)        return -1;    int cur = left;    int prev = left-1;    int key = arr[right];    while (cur <= right)    {        if (arr[cur] <= key && arr[++prev] != arr[cur])            Swap(arr[prev], arr[cur]);        cur++;    }    return prev;}void QuickSort(int arr[], int left, int right){    if (arr == NULL || left <0 || left>right)        return;    int index = Partition3(arr, left, right);    if (index > left)        QuickSort(arr, left, index - 1);    if (index < right)        QuickSort(arr, index + 1, right);}#endif//#####################################################ifndef __SELECTSORT_H__#define __SELECTSORT_H__#include "QuickSort.h"#include <stdio.h>#include <stdlib.h>/*#######################################################################################快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。步骤:从数列中挑出一个元素,称为 “基准”(pivot),重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序########################################################################################*/void Select_Sort1(int arr[],int left,int right)  //冒泡思想{    //第一个数依次与后面的所有数进行比较,找最小数    for (int i = left; i < right; i++)    for (int j = i + 1; j <= right; j++)    {        if (arr[i]>arr[j])            Swap(arr[i], arr[j]);    }}//##############################################################//选择排序//1.在未排序的元素中找到最小的元素,,放在数组首//2.在剩余未排序的元素中找最小数,续在已排好序的尾部void Select_Sort2(int arr[], int left, int right)  //选择最小数下标,先保存第一个数的下标,                                                   //在依次比较第一个数与其他数,保存最小数下标,交换{    for (int i = left; i <= right; i++)    {        int min = i;//保存下标        for (int j = i+1; j<=right; j++)//判断        {            if (arr[min] > arr[j])                min = j;        }        if (min != i){            Swap(arr[min], arr[i]);        }    }}/*##############################################################二叉堆满足二个特性:1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。堆的存储一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。在堆的数据结构中,堆中的最大值总是位于根节点。堆中定义以下几种操作:最大堆调整(Max_Heapify):将堆的末端子结点作调整,使得子结点永远小于父结点创建最大堆(Build_Max_Heap):将堆所有数据重新排序堆排序(HeapSort):移除位在第一个数据的根结点,并做最大堆调整的递归运算*/    void BuildHeap(int arr[], int parent ,int k ){    if (arr == NULL)        return;    int leftchild = parent * 2 + 1;    int rightchild = parent * 2 + 2;    while (leftchild < k)    {        if (rightchild<k && arr[rightchild]>arr[leftchild])            ++leftchild;        if (arr[leftchild]>arr[parent])        {            Swap(arr[parent], arr[leftchild]);            parent = leftchild;            leftchild = parent * 2 + 1;        }        else            break;    }}void Heap_Sort(int arr[], int num,int left,int right)//堆排序{    //arr 待调整数组 right+1 为数组长度 num 为要调整的位置    //建立一个堆    //写堆的向下调整算法(交换堆顶和末尾元素)    //输入数据,调整    if (arr == NULL)        return;    for (int parent = (right + 1) / 2; parent >= 0; parent--)        BuildHeap(arr, parent, right);    for (int i = right; i > 0; i--)    {        Swap(arr[0], arr[i - 1]);        BuildHeap(arr, 0, i - 1);    }}#endif#ifndef __MERGE_H__#define __MERGE_H__#include <iostream>#include <stdio.h>#include <stdlib.h>using namespace std;/*###############################################################归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用步骤:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列设定两个指针,最初位置分别为两个已经排序序列的起始位置比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置重复步骤3直到某一指针达到序列尾将另一序列剩下的所有元素直接复制到合并序列尾#################################################################*///归并排序//分治法,把一个N规模的问题划分为若干相同思路的小问题//动态规划中有自顶向下和自底向上两种思路,这里是自底向上//新开辟一个同样大小的空间作为中转//1.分解,将当前区域一分为二   mid = (left+right)/2//2.求解,递归子问题将区域划分为两个子问题//3.当最后剩余两个时,进行比较,排序,归并void Merge(int arr[],int temp[],int left,int mid, int right)//归并排序{    if (arr == NULL || left < 0)        return;    int begin1 = left;    int begin2 = mid+1;    int k = left ;    //两段区域比较大小,依次把小值放在temp[]    while (begin1 != mid+1 && begin2 != right+1)    {        if (arr[begin1] < arr[begin2])            temp[k++] = arr[begin1++];        else            temp[k++] = arr[begin2++];    }    //处理一段区域内较长部分(可以用if判断,下面的两个循环只能进去一个)    while (begin1 < mid+1)        temp[k++] = arr[begin1++];    while (begin2 <= right)        temp[k++] = arr[begin2++];    //将temp[]中的数拷贝回去    for (int i = left; i <= right; i++)        arr[i] = temp[i];}void MergeSort(int arr[], int temp[],int left, int right){    if (arr == NULL)        return;    int mid;    if (left < right)    {        mid = (left + right) / 2;        MergeSort(arr,temp, left, mid);        MergeSort(arr, temp,mid + 1, right);        Merge(arr,temp,left, right, mid);    }}#endif//################################################include "QuickSort.h"#include "InsertSort.h"#include "BubbleSort.h"#include "SelectSort.h"#include "MergeSort.h"int main(){    int arr[10] = { 3, 5, 7, 1, 2, 8, 9, 5, 3, 0 };    //int arr[10] = { 2, 2, 2, 4, 1, 4, 7, 5, 9, 0 };    int temp[10];    for (int i = 0; i <10; i++)    {        printf("%d ", arr[i]);    }    printf("\n");    int left = 0;    int right = sizeof(arr) / sizeof(arr[0])-1;//####################################################//测试函数    //QuickSort(arr, left, right);    //BubbleSort1(arr, left, right);    //BubbleSort2(arr, left, right);    //InsertSort(arr, left, right);    //Select_Sort2(arr, left, right);    //Heap_Sort(arr, left, right);      MergeSort(arr, temp, left, right);//####################################################    for (int i = 0; i <=right; i++)    {        printf("%d ", arr[i]);    }    printf("\n");    return 0;}