wly603

各种排序算法的总结

概要:

    这是本人以前学习数据结构时,写的一些排序算法。今天整理一下,方便以后查阅。

   本文实现的排序算法包括:直接插入排序、折半插入排序、2路插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序

一、具体实现

      关于各算法的特点和思想原理,本文不作介绍,需要了解的,可查阅数据结构书籍,或直接google

        

直接插入排序
//直接插入排序:参数:待排序数据,数据个数
void InsertSort( int nData[], int nNum)
{
    int temp= 0; //哨兵
    int i,j;
    for (i = 1;i<nNum;i++)
    {
        if (nData[i] < nData[i-1])
        {
            temp = nData[i];
            //for (j = i-1; j>=0 && temp < nData[j]; j--)
            for (j = i-1; j>=0; j--)
            {
                if (temp < nData[j])
                    nData[j+1] = nData[j];
                else 
                    break;
            }
            nData[j+1] = temp; //插入数据
            
        }
    
    }
}
折半插入排序
//折半插入排序
void BInsertSort(int nData[],int nNum)
{
    int i,j,low,high;
    int mid;//中间值
    int temp;//哨兵
    for (i = 1;i<nNum; i++)
    {
                /////我觉得最好加入判断:if (nData[i] < nData[i-1]),这可减少比较次数
        temp = nData[i];

        low = 0;
        high = i-1;
        while (low <= high)
        {
            mid = (low+high)/2;  //折半
            if (temp < nData[mid])
                high = mid-1;  //插入点在低半区
            else
                low = mid+1; //插入点在高半区
            
        }//找到插入点位置,为high。

        for (j = i-1;j>= high+1;j--)
            nData[j+1]=nData[j];

        nData[j+1] = temp;//将新数据插入到high+1
    }
}
2路插入排序
//2路插入排序
void P2_InsertSort(int nData[], int nNum)
{
    int i=0;
    int first = 0,final = 0;
    int *d = new int[nNum];
    d[0] = nData[0];//第0个元素

    for (i = 1; i<nNum; i++)
    {
        if (nData[i]<d[first])  //插入到最前面
        {
            first = (first-1+nNum)%nNum;  //当first为0时,插入位置是最后一个。所以要加nNum
            d[first] = nData[i];
        }
        else  if(nData[i]>d[final]) //插入到最后面
        {
            final = (final+1)%nNum;
            d[final] = nData[i];
        }
        else
        {
            int j = final++;
            while (nData[i] < d[j])//移动尾部数据
            {
                d[(j+1)%nNum] = d[j];
                j = (j-1+nNum)%nNum;
            }
            d[j+1] = nData[i];//进行插入
        }
    }

    for (i=0 ;i<nNum;i++)//把数据赋给原数组
    {
        nData[i] = d[first];
        first = (first+1)%nNum;
    }

    delete []d;

}
希尔排序
//////////////////////////////////////////////////////////////////////////
//希尔排序
//第一种写法
//其中的一组排序
void ShellInsert_1(int nData[], int nNum, int nBegin,int nStep)
{
    int i,j;
    int temp;
    for (i = nBegin + nStep;i<nNum; i+=nStep)//从nBegin点的下一个点,开始进行插入
    {
        temp = nData[i];
        if (temp < nData[i-nStep])
        {
            for (j= i-nStep; j>=nBegin&&temp<nData[j]; j-=nStep)//j>=nBegin
            {
                nData[j+nStep] = nData[j];
            }
            nData[j+nStep] = temp;  //插入
        }
    }
}

void ShellSort_1(int nData[],int nNum)
{
    int i,nStep;
    //以nStep分组,nStep每次减为原来的一半
    for(nStep = nNum/2; nStep>0; nStep /=2 )//趟数
    {
        //对每个组进行排序
        for (i=0; i<nStep; i++)
        {
            ShellInsert_1(nData,nNum,i,nStep);
        }
    }
}

//第2种写法
/*一趟希尔插入排序*/
void ShellInsert_2(int nData[],int nNum,int nStep)
{
    int i,temp;
    for (i = nStep;i<nNum;i++) //i++
    {
        if (nData[i]<nData[i-nStep])
        {
            temp = nData[i];
            for (int j=i-nStep;j>=0&&temp<nData[j]; j-=nStep )//由于数组是从0开始取,所以j>=0
            {
                nData[j+nStep] = nData[j];
            }
            nData[j+nStep] = temp;
        }
    }
}
void ShellSort_2(int nData[],int nNum)
{
    int nStep;
    for (nStep = nNum/2; nStep>0; nStep /= 2)
    {
        ShellInsert_2(nData,nNum,nStep);
    }
}
冒泡排序
//冒泡排序
void BubbleSort(int nData[],int nNum)
{
    int i,j;
    int temp;//用于交换
    bool flag = false;//标志:是否有交换

    for (i=0; i<nNum-1; i++)//nNum-1趟
    {
        flag = false;
        for(j=0; j<nNum-1-i; j++)
        {
            if (nData[j]>nData[j+1])
            {
                temp = nData[j];
                nData[j] = nData[j+1];
                nData[j+1] = temp;
                flag = true; //有交换,标志置1
            }
        }

        if (!flag)
        {
            break;
        }
    }
    printf("\n总共排了  %d 趟\n",i+1);
}
快速排序
//快速排序
//第一种写法:是参照《数据结构基础(第二版c语言)》写的
void QuickSort_1(int nData[],int left,int right)//选取第一个作为枢纽
{
    int pivot,i,j;
    int temp;
    if (left < right)
    {
        i = left;
        j = right+1;
        pivot = nData[left];

        do
        {
            do 
            {
                i++;
            } while (nData[i] < pivot);
            
            do 
            {
                j--;
            } while (nData[j] > pivot);

            if(i<j) //交换 nData[i]与nData[j]
            {
                temp = nData[i];
                nData[i] = nData[j];
                nData[j] = temp;            
            }

        }while (i<j);

    

        nData[left] = nData[j];//交换nData[left]与nData[j]
        nData[j] = pivot;

        QuickSort_1(nData,left,j-1);//递归排左半部分
        QuickSort_1(nData,j+1,right);//递归排右半部分
    
    }// end if(left<right)
}
//第二种写法:参照《严蔚敏:数据结构(c语言版)》写的
void QuickSort_2(int nData[],int left,int right)//选取第一个作为枢纽
{
    int i,j,pivot;
//    int temp;
    if (left < right)
    {
        pivot = nData[left];//先把枢纽值备份
        i = left;
        j = right;

        while (i<j)
        {
            while(i<j && nData[j]>=pivot)
                j--;//找到右边的小数的位置

            nData[i] = nData[j];//把右边的小数放到左边,即放到nData[i]

            while(i<j && nData[i]<=pivot)
                i++;//找到左边的大数的位置

            nData[j] = nData[i];//把左边的大数放到右边,即放到nData[j]

        }
        nData[i] = pivot;//把枢纽值填进来
    //    printf("\n%d  %d\n",i,j);//此时i,j的值相等

        QuickSort_2(nData,left,i-1);
        QuickSort_2(nData,i+1,right);
    }
}

接下来的快排是参照:  公开课: MIT 算法导论 中  快速排序

MIT-算法导论-快速排序
/************************************************************************/
/* 公开课: MIT 算法导论 中  快速排序
*   Partion()方法
*                                                                    
/************************************************************************/
void exchange(int &x,int &y)//交换
{
    int temp;
    temp =x;
    x = y;
    y =temp;
}

int Partion(int a[],int start,int end)
{
    int pivot = a[start]; //枢轴

    int i = start;//i 用来存比pivotkey小的一系列数的最后一个数的下标
    for (int j= start+1 ; j<=end ;j++)  //一次遍历,找到枢轴所在的位置
    {
        if ( a[j] < pivot) //把所有小的数,移到前面
        {
            i =i+1;
            exchange(a[j],a[i]);        
        }
    }
    exchange(a[i],a[start]);

    return i; //i是枢轴的位置
}

void QSORT(int a[],int start,int end)
{
    if (start < end)
    {
        int pivotloc = Partion(a,start,end);
        QSORT(a,start,pivotloc-1);
        QSORT(a,pivotloc+1,end);
            
    }
}

void QS(int a[],int n)
{
    QSORT(a,0,n-1);
}
简单选择排序
void SelectSort(int nData[],int nNum)
{
    int i,j,temp;
    for (i = 0;i < nNum-1; i++)
        for(j = i+1; j<nNum;j++)
        {
            if(nData[i] > nData[j])
            {
                temp = nData[i];
                nData[i] = nData[j];
                nData[j] = temp;
            }
        }
}
堆排序
//堆排序:(包括两个步骤:建堆和排序)
//第一步:建堆(大根堆),二叉树的标号是从1,2,…,nNum
void HeapAdjust(int nData[],int s, int nNum) //s表示父节点的标号,nNum表示总结点数
{
    int temp,j;//j表示左孩子的二叉树标号
    int t;//用t记录结点对应的数组下标,则t=s-1

    t=s-1;
    temp = nData[t];//temp记录父结点s的值


    for (j = 2*s; j<=nNum; j*=2)
    {
        t = j-1;//此时t表示左孩子的数组下标
        if (j<nNum && nData[t]<nData[t+1])  //左孩子比右孩子小
        {
            ++j;  //用j记录较大孩子的二叉树下标
        }

        if (temp >= nData[j-1]) //如果当前父节点比最大孩子的值还大,说明已经是最大堆
        {
            break;   //那么跳出循环
        }
        else
        {
            nData[s-1] = nData[j-1];//把最大孩子的值赋给当前父节点
            s=j;//把父节点更新到最大的孩子,进入下一轮判断
        }
    }
    nData[s-1] = temp; //把原父节点s的值插入到大根堆中
}
//第二步:堆排序
void HeapSort(int nData[],int nNum)
{
    int i,temp;//i表示二叉树的标号,取值范围为1:nNum
    int j;//表示对应的数组下标,取值范围为:0:nNum-1,故j=i-1;
    for (i = nNum/2;i>0; i--)//对标号从1到nNum的结点进行建堆
    {
        HeapAdjust(nData,i,nNum);//从最后一个非终端结点开始,建堆
    }

    for (i = nNum;i>1; i--) //i表示二叉树的标号
    {
        temp = nData[i-1]; //交换,即把根(即最大值),放到数组的最后一个元素中
        nData[i-1] = nData[0];
        nData[0] = temp;

        HeapAdjust(nData,1,i-1);//将剩下的i-1个结点重新调整为大根堆
    }

}
归并排序
//归并排序: 
//第一种写法:递归形式。(包括两个步骤: 归并和递归排序)
//第一步 归并:
//将nData[left..center]和nData[center+1..len], 从小到大,归并为有序的nData[left..len]
void Merge(int nData[],int left,int center, int len)
{
    int *temp = new int [len+1-left];
    int k = 0;//k是temp数组的下标索引
    int i,j;//i是nData[left..center]数组的下标索引
            //j是nData[center+1..len]数组的下标索引
    for (i=left,j=center+1; i<=center&&j<=len; k++)
    {
        if (nData[i] <= nData[j])
            temp[k] = nData[i++];
        else
            temp[k] = nData[j++];
    }

    while (i<= center)//归并剩余的部分
    {
        temp[k++] = nData[i++];
    }
    while (j <= len)
    {
        temp[k++] = nData[j++];
    }

    for (i=left,j=0; i<=len&&j<k; i++)//temp[]中的元素复制回原数组nData[]
    {
        nData[i] = temp[j++];
    }

    delete []temp;

}
//第二步:递归排序
//参数:nData[]待排序的数组,left起点的数组下标,right终点的数组下标
void MSort(int nData[],int left,int right)
{    
    if (left < right)
    {
        int center;//原数组进行划分,一分为二。center为中点
        center = (left+right)/2;
        MSort(nData,left,center);//左边部分进行递归的排序
        MSort(nData,center+1,right);//右边
        Merge(nData,left,center,right);//将排序的左右两边进行归并
    }
}
//归并排序,第二种写法,非递归形式(non-recursive)
//参数:nData[]待排数据,nNum:nData[]的元素个数
void Msort_NRecur(int nData[],int nNum)
{
    int pre_Len = 1; //合并前的序列长度
    int after_Len = 1; //合并后的序列长度

    for (; after_Len<nNum; pre_Len = after_Len )//合并后的长度小于nNum,则继续合并
    {
        after_Len = pre_Len*2;//合并后的长度是合并前的2倍

        int i=0;//合并的序列下标,从0开始
        for (; i+after_Len-1 <= nNum-1; i+=after_Len)//元素下标范围是0..nNum-1
        {
            Merge(nData,i,i+pre_Len-1,i+after_Len-1);
        }

        if (i+pre_Len <= nNum-1)//把最后那段长度不足after_Len,但超过pre_Len的序列合并
        {
            Merge(nData,i,i+pre_Len-1,nNum-1);
        }
    }
}
主函数main
void main()
{
//    int a[max]={4,4,9,5,17,6,20,45,30,54,25};   
    int a[max]={3,13,56,34,14,46,34,6,9,56,20};
    printf("直接插入排序\n\n请输入 %d 个待排序的整数:\n",max);

    int i;
//     for (i=0;i<max;i++)
//     {
//         scanf("%d",&a[i]);
//     }
    
    printf("\n\n原始数据   待排序的整数为:\n");
    for ( i=0;i<max;i++)
    {
        printf("%d\t",a[i]);
    }

//    InsertSort(a,max);
//    BInsertSort(a,max);
//    P2_InsertSort(a,max);
//    ShellSort_2(a,max);
//    BubbleSort(a,max);
    QuickSort_2(a,0,max-1);
//    QS(a,max);
//    SelectSort(a,max);
//    HeapSort(a,max);
//    MSort(a,0,max-1);
//    Msort_NRecur(a,max);

    printf("\n直接插入排序,结果为:\n");
    for ( i=0;i<max;i++)
    {
        printf("%d\t",a[i]);
    }

}

 

二、总结

      实现一遍后,对各算法都理解了。不知为啥,项目中一碰到要排序,立马就是冒泡!why?

posted on 2012-05-08 09:20  wly603  阅读(340)  评论(0编辑  收藏  举报

导航