基本排序总动员


#include <stdio.h>
#define MAXSIZE 200
/* 冒泡排序
 * 选择排序
 * 插入排序
 * 快速排序
 * 希尔排序
 * 折半插入排序
 */
typedef struct _node {
 int elem[MAXSIZE+1];
 int length;  // length = MAXSIZE
} node;
/* 冒泡排序 */
node *bubblesort(node *L)  // 排序后单调不减 
{
 int i, j, flag;
 node *head;
 for (i=1; i<L->length; i++)  // 最坏n-1趟
 {
  flag = 0;
  for (j=1; j<L->length-i+1; j++)  // 记住: 一个for就可以解决一趟冒泡. :-)
   if (L->elem[j] > L->elem[j+1])
   {
    flag = 1;
    L->elem[0] = L->elem[j];
    L->elem[j] = L->elem[j+1];
    L->elem[j+1] = L->elem[0];
   }
  if (flag == 0) // 判断有序依据
   break;
 }
 return (head);
}
/* 选择排序 */
node *selectsort(node *L) // 排序后单调不增
{
 node *head = L;
 int i, j, k;
 for (i=1; i<L->length; i++)  // n-1趟
 {
  L->elem[0] = L->elem[i];
  k = i;  // not forget!
  for (j=i+1; j<=L->length; j++)  // 从头到尾依次排好.
   if (L->elem[j] > L->elem[0])
   {
    L->elem[0] = L->elem[j];
    k = j;
   }
  if (k != i)
  {
   L->elem[0] = L->elem[k];
   L->elem[k] = L->elem[i];
   L->elem[i] = L->elem[0];
  }
 }
 return (head);
}
/* 插入排序 */
node *insertsort(node *L) // 排序后单调不减
{
 node *head = L;
 int i, j;
 for (i=2; i<=L->length; i++)
  if (L->elem[i-1] > L->elem[i])
  {
   L->elem[0] = L->elem[i];
   L->elem[i] = L->elem[i-1];
   for (j=i-2; L->elem[j] > L->elem[0]; j--) // 考虑2个元素且相等情形, 较易理解.
     L->elem[j+1] = L->elem[j];
   L->elem[j+1] = L->elem[0];
  }
 return (head);  
}
int partition(node *L, int low, int high)  // 按枢轴shu1进行划分, 并返回最终枢轴的位置信息.
{
 L->elem[0] = L->elem[low]; 
 while (low < high)
 {
  while (low < high && L->elem[high] <= L->elem[0])
   high--;
  L->elem[low] = L->elem[high]; // 算法每次的赋值过程,实际上可以抽象为空出一格来.
  while (low < high && L->elem[low] >= L->elem[0])
   low++;
  L->elem[high] = L->elem[low];
 }
 L->elem[low] = L->elem[0];  // 此时只要经过了上面的大while,则low = high.
 return low;
}
void qsort(node *L, int low, int high)
{
 int pivotloc;
 if (low < high) // 不是 while
 {
  pivotloc = partition(L, low, high);
  qsort(L, low, pivotloc-1);
  qsort(L, pivotloc+1, high);
 }
 return ;
}
/* 快速排序 */
node *quicksort(node *L)   // 排序后单调不增
{                          // 关键点: 1. 按枢纽点分区; 2. 递归(包括不断分区).
  node *head = L;
  qsort(L, 1, L->length);
  return (head);
}
/* 希尔排序 */
node *shellsort(node *L)   // 排序后单调不减
{
 node *head = L;
 int i, j;
 int dk = (L->length+2)/2; // decided by use case, 如果不同dk有公因子,也能完成排序, 影响的只是时间复杂度.
 while (dk>0)
 {
  for (i=dk+1; i<=L->length; i++)  // dk = 1时,是直接插入排序法, 保证有dk = 1情形,就可以保证排序成功.
   if (L->elem[i] < L->elem[i-dk])
   {
    L->elem[0] = L->elem[i];
    j = i - dk;
    while (j>0 && L->elem[0]<L->elem[j])
    {
     L->elem[j+dk] = L->elem[j];
     j = j - dk;
    }
    L->elem[j+dk] = L->elem[0];
   }
  dk = dk/2;
 }
 return (head);
}
/* 折半插入排序 */
node *binaryinsertsort(node *L)  // 排序后单调不增
{
 node *head = L;
 int i, j, low, high, mid;
 for (i=2; i<=L->length; i++)
 {
  low = 1; high = i-1;  // i-1
  L->elem[0] = L->elem[i]; // elem[i] 是待插入的元素.
  while (low <= high)
  {
   mid = (low+high)/2;
   if (L->elem[mid] > L->elem[0]) // elem[mid] 和 elem[0] 比较. 
    high = mid - 1;
   else 
    low = mid + 1;                // 将EQ的结果放在这里,是为了得到high值,可以验证.
  }
  for (j = i; j>high+1; j--) // not ">=";
    L->elem[j] = L->elem[j-1];
  L->elem[high+1] = L->elem[0];
 }
 // so ugly, for符合单调不增, 而不改动上面的主体.
 int t[L->length+1];
 for (i=L->length; i>0; i--)
  t[L->length-i+1] = L->elem[i];
 for (i=1; i<=L->length; i++)
  L->elem[i] = t[i];
    
 return (head);
}
void kprint(node *L)
{
 static int count = 1;
 printf("Print times: %d/n", count);
 int i;
 for (i=0; i<L->length; i++)
   printf("%2d ", L->elem[i+1]);
 printf("/n/n");
 count++;
 return ;
}
int main()
{
  int i;
  node mytest;
  mytest.length = MAXSIZE;
  for (i=1; i<=MAXSIZE; i++)
   mytest.elem[i] = MAXSIZE - i + 1;
  kprint(&mytest);
  
  bubblesort(&mytest); 
  kprint(&mytest);
  selectsort(&mytest);
  kprint(&mytest);
  
  insertsort(&mytest);
  kprint(&mytest);
  quicksort(&mytest);
  kprint(&mytest);
  
  shellsort(&mytest);
  kprint(&mytest);
  binaryinsertsort(&mytest);
  kprint(&mytest);
  return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值