排序总结:插入(简单和改进)、希尔、选择、冒泡、快速、堆排序、归并排序

插入:基础的、改进的、希尔
选择:基础的、堆排序
交换:冒泡、快排及其改进
归并:将两个已经排好序的文件归并成一个有序的大文件(比较适合链表)

typedef int Item;
#define key(A) (A)
#define eq(A,B) (key(A) == key(B))
#define less(A,B) (key(A) < key(B))
#define exch(A,B) {Item t = A;A = B; B =t;}
#define compexch(A,B) if(less(B,A)) exch(A,B)
#define min(A,B) A < B ? A : B
//基础的插入排序
void simpleinsertsort(Item a[],int l,int r)
{
    int i,j;
    for(i = l+1;i <= r;i++)
        for(j = i;j > l;j--)
        compexch(a[j-1],a[j]);  //从i处往前对比,把小的移到前面!
}

//改进的插入排序
void insertsort(Item a[],int l,int r)
{
     int i,j;
     Item v;
     for(i = r;i > l;i--)
        compexch(a[i-1],a[i]);  //将最小值放在首位
     for(i = l+2;i <= r;i++)
     {
         j = i;
         v = a[i];
         while(less(v,a[j-1]))  //与当前索引值比较,比v大就将其右移,否则退出,
         {
             a[j] = a[j-1];      //只是赋值,并不交换
             j--;
         }
         a[j] = v;            //此时j+1与i之间的数都是比v大的,将v插入在j
     }
}
//希尔排序
void shellsort(Item a[],int l,int r)  //对步长的选择很重要(h要取到1)
{
      int h,i,j;
      for(h = 1;h <= (r-l)/7;h = 3*h+1);  //创建一个步长序列,最终h要取到1
      for(;h > 0;h = h/3)               //对每一个步长都要进行一次扫描排序
       for(i = l+h;i <= r;i++)         //从l+h开始:因为后面有对j-h的比较,
      {
          j = i;
          Item v = a[j];
          while(j-h >= l && less(v,a[j-h])) //这一循环与insertsort的思想一样
            {
                a[j] = a[j-h];          //只不过insert是h=1,这里的步长h可变
                j = j-h;
            }
            a[j] = v;
      }
}

//选择排序
void selectsort(Item a[],int l,int r)
{
    int i,j,Min;
    for(i = l;i < r;i++)               //当前索引左边的元素都是排好序的(最终位置)
    {
        Min = i;
        for(j = i+1;j <= r;j++)      //从左到右,记录最小元素下标,
            if(less(a[j], a[Min]))
             Min = j;
        exch(a[i],a[Min]);           //将最小元素交换到相应位置
    }
}
//堆排序
void fixDown(Item *pq,int k,int N)   //自顶向下堆化
{
    int j;
    while(2*k <= N)
    {
        j = 2*k;
        if(j < N && less(pq[j],pq[j+1]))  //找到子节点中的较大值
           j++;
        if(!less(pq[k],pq[j]))           //若较大值小于父节点就结束,否则交换子父节点
            break;
        exch(pq[k],pq[j]);
        k = j;
    }
}

void heapsort(Item a[],int l,int r)
{
    Item *pq = a;
    int k,N = r-l;
    for(k = N/2;k >= l;k--)  //将最大值交换到数组首位
        fixDown(pq,k,N);
    show(a,l,r);
    while(N > 0)
    {
        exch(pq[0],pq[N]);   //每次将首位元素(剩余数组元素中最大值)与最后的元素交换
        fixDown(pq,0,--N);   //接着数组大小-1,将剩余元素堆化,接着下一轮循环
    }
}
//冒泡排序
void bubblesort(Item a[],int l,int r) //遍历文件,依次比较相邻元素,将最小值排到前面
{
     int i,j;
     for(i = l;i < r;i++)
        for(j = r;j > i;j--)  //for(j = l+1;j <= i;j++)也可以用前面的循环
        compexch(a[j-1],a[j]);
}
//快速排序中的划分函数
int qpartition(Item a[],int l,int r)
{
    Item v = a[r];
    int i,j;
    i = l;
    j = r-1;
    for(;;)
    {
        while(less(a[i],v))  //左扫描,划分元素v左边不大于v
            i++;
        while(less(v,a[j]))  //右扫描,划分元素v右边不小于v
            {
                j--;
                if(j == l)
                    break;
            }
        if(j <= i)
            break;
        exch(a[i],a[j]);   //左扫描大于v的元素与右扫描小于v的元素交换
    }
    exch(a[r],a[i]);   //划分结束,将划分元素置换到结束位置
    return i;
}
//基本的快排:
void quicksort(Item a[],int l,int r)
{
    int i;
    if(r < l)
        return;
    i = qpartition(a,l,r);
    quicksort(a,l,i-1);
    quicksort(a,i+1,r);
}
//三路取中快排:取待排序列的首、中、尾三个元素,取大小居中的作为划分元素
void quicksortMid(Item a[],int l,int r)
{
    if(r-l <= 3)
       {
            simpleinsertsort(a,l,r);  //当数组小于某一大小时,就采用插入操作
            return;
       }
    exch(a[(l+r)/2],a[r-1]);
    compexch(a[l],a[r-1]);
    compexch(a[l],a[r]);
    compexch(a[r-1],a[r]);  //将三者中的中间元素放于r-1处,v=a[r-1]
    int i = qpartition(a,l+1,r-1); //v=a[r-1]
    quicksortMid(a,l,i-1);
    quicksortMid(a,i+1,r);
}
//三路划分快排:将待排序列分为三路:小于v、等于v、大于v
void quicksortDiv(Item a[],int l,int r)
{
     if(r <= l)
        return;
     int i,j,p,q;
     Item v = a[r];
     i = l;
     j = r;
     p = l;
     q = r-1;
     for(;;)
     {
         while(less(a[i],v)) i++;
         while(less(v,a[--j]))
            if(j == l)
              break;
            if(j <= i)
                break;
        exch(a[i],a[j]);
        if(eq(a[i],v))
            {
                exch(a[p],a[i]);   //需要对数组下标进行自加或自减时,最好与数组元素的引用分开
                p++;               //就如左边两句:先交换,然后再自加得到下一元素的下标!否则,有可能交换到相邻位置
            }
        if(eq(a[j],v))
            {
                exch(a[q],a[j]);
                q--;
            }
     }
     exch(a[i],a[r]);   //这里a[r]不能用v代替,否则a[i]处存的是v,但是a[r]处没变
     j = i-1;
     i = i+1;
     while(p > l)
        {
            p--;
            exch(a[p],a[j]);
            j--;
        }
     while(q < r-1)
        {
            q++;
            exch(a[i],a[q]);
            i++;
        }
     quicksortDiv(a,l,j);
     quicksortDiv(a,i,r);
}
//利用快排里的划分函数来寻找序列中第k个最小元素(非递归的形式、递归的调试未成功,成功后再上传)
int selectsortPar2(Item a[],int l,int r,int k)
{
   int i;
    while(r > l)
    {
       i = qpartition(a,l,r);
       if(i < k)
        l = i+1;
       if(i > k)
        r = i-1;
       if(i == k)
        break;
    }
    return a[i];
}
//归并排序:会用到大量的额外空间,如果两个待归并序列并不有序,可以先排序,再将其进行归并
void mergesort(Item c[],Item a[],int N,Item b[],int M)
{
    int i,j,k;
    for(i = 0,j = 0,k = 0;k < N+M;k++)
    {
        if(i == N)
        {
            c[k] = b[j];
            j++;
            continue;
        }
        if(j == M)
        {
            c[k] = a[i];
            i++;
            continue;
        }
        if(a[i] < b[j])
        {
            c[k] = a[i];
            i++;
        }
        else if(a[i] >= b[j])
        {
            c[k] = b[j];
            j++;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值