排序算法總結

shell 排序算法總結

Latest Snippet Version: 1.01

/*
* Shell 排序算法在 1959 年由 D. Shell 發明。
* 也稱爲遞減增量排序算法,各種實現在如何進行遞減上有所不同。
* 不穩定,不需要輔助空間。
*/
/*
* Gonnet 算法,發表於 1991 年。
*/
int shellsortGo(int p[],int n)
{
int op=0;
int h,i,j,temp;
for(h=n; h>1; ) {
   h=(h<5)?1:(h*5-1)/11;
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Incerpj-Sedgewick 算法,1985 年發表。
*/
int shellsortIS(int p[],int n)
{
int op=0;
int h,i,j,t,temp;
int incs[16] = { /* a1=3,a2=7,a3=16,a4=41,a5=101 */     
   1391376,   /* a1*a2*a3*a4*a5 */
   463792,   /* a2*a3*a4*a5 */
   198768,   /* a1*a3*a4*a5 */
   86961,   /* a1*a2*a4*a5 */
   33936,   /* a1*a2*a3*a5 */
   13776,   /* a1*a2*a3*a4 */
   4592,   /* a2*a3*a4 */
   1968,   /* a1*a3*a4 */
   861,   /* a1*a2*a4 */
   336,   /* a1*a2*a3 */
   112,   /* a2*a3 */
   48,    /* a1*a3 */
   21,    /* a1*a2 */
   7,   /* a2 */
   3,   /* a1 */
   1
};
for(t=0; t<16; t++) {
   h=incs[t];
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Sedgewick 算法,1986 年發表。Knuth 推薦。
*/
int shellsortSe(int p[],int n)
{
int op=0;
int h,i,j,t,temp;
int incs[18] = {
   1045505, 587521, 260609, 146305, 64769,
   36289, 16001, 8929, 3905, 2161, 929,
   505, 209, 109, 41, 19, 5, 1
};
/* if (i%2) h[i]=8*pow(2,i)-6*pow(2,(i+1)/2)+1;
* else h[i]=9*pow(2,i)-9*pow(2,i/2)+1; */
    for (t=0; t<18; t++) {
   h=incs[t];
   if (h>n/3)
    continue;
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Tokuda(徳田尚之)算法。發表於 1992 年。
*/
int shellsortTo(int p[],int n)
{
int op=0;
int h,i,j,t,temp;
int incs[18] = {
   1747331, 776591, 345152, 153401, 68178,
   30301, 13467, 5985, 2660, 1182, 525,
   233, 103, 46, 20, 9, 4, 1
};
/* h[i]=ceil((9*pow(2.25,i)-4)/5) */
    for (t=0; t<18; t++) {
   h=incs[t];
   if (h>n*4/9)
    continue;
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Ciura 算法。發表於 2001 年。性能卓越。
*/
int shellsortCi(int p[],int n)
{
int op=0;
int h,i,j,t,temp;
int incs[18] = {
   2331004, 1036002, 460445, 204643, 90952,
   40423, 17965, 7985, 3549, 1577, 701,
   301, 132, 57, 23, 9, 4, 1
};
    for (t=0; t<18; t++) {
   h=incs[t];
   if (h>n*4/9)
    continue;
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*******************************************/
/* 下面幾個算法有研究價值                  */
/*******************************************/
/*
* D. Shell 最初的算法。
*/
int shellsortSh(int p[],int n)
{
int op=0;
int h,i,j,temp;
for(h=n/2; h>0; h=h/2) {
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Lazarus-Frank 算法,1960 年發表。
* 原爲在必要時加 1 使所有增量都爲奇數, 現修正爲減 1。
*/
int shellsortLF(int p[],int n)
{
int op=0;
int h,i,j,temp;
for(h=n/2; h>0; h=h/2) {
   if (h%2==0)
    h--;
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*--------------------------------------*/
/*
* Hibbard 算法,1963 年發表。
* 1965 年 Papernov-Stasevich 給出了數學證明。
*/
int shellsortHb(int p[],int n)
{
int op=0;
int h,i,j,temp;
for(h=1; h<=n/4; h=h*2+1);
for( ; h>0; h=(h-1)/2) {
/* h = 1, 3, 7, 15, 31 ... 2^i-1 */
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Papernov-Stasevich 算法, 1965? 年發表。
*/
int shellsortPS(int p[],int n)
{
int op=0;
int h,i,j,temp;
for(h=2; h<=n/4; h=h*2-1);
for( ; h>1; ) {
   h=(h==3)?1:(h+1)/2;
   /* h = 1, 3, 5, 9, 17, 33 ... 2^i+1 */
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Knuth 算法,他建議在 n<1000 時使用。
*/
int shellsortKn(int p[],int n)
{
int op=0;
int h,i,j,temp;
for(h=1; h<=n/9; h=h*3+1);
for( ; h>0; h=h/3) {
/* h = 1, 4, 13, 40, 121, 364... 3*h+1 */
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*--------------------------------------*/
/*
* Pratt 算法,1971 年發表。
* 原爲 h=2^p*3^q 現修正爲 7^p*8^q。
*/
int shellsortPr(int p[],int n)
{
int op=0;
int h,i,j,t,temp;
int incs[28] = {
   262144, 229376, 200704, 175616, 153664, 134456,
   117649, 32768, 28672, 25088, 21952, 19208, 16807,
   4096, 3584, 3136, 2744, 2401, 512, 448, 392, 343,
   64, 56, 49, 8, 7, 1
};
for(t=0; t<28; t++) {
   h=incs[t];
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}
/*
* Sedgewick 算法, 1982 年發表。
*/
int shellsortSe82(int p[],int n)
{
int op=0;
int h,i,j,t,temp;
for (t=1; t*t<=n/4; t+=t);
    for (h=n/4; t>0; t/=2, h=t*t-(3*t)/2+1) {
/* h = 1, 8, 23, 77, 281, 1073, 4193, 16577,
* 65921, 262913, 1050113... 4^i+3*2^(i-1)+1 */
   for (i=h; i<n; i++) {
    temp=p[i];
    for (j=i-h; j>=0 && p[j]>temp; j-=h) {
     p[j+h]=p[j];
     op++;
    }
    p[j+h]=temp;
    op++;
   }
}
return op;
}

兩分法查找例程
==============================================
Latest Snippet Version: 1.0


int binarysearch(int p[],int n,
   int value, /* 查找值 */
   int *m) /* 返回的是第一個大於等於查找值的元素
            * 位置和小於查找值的元素個數 */
{
int op=0;
int i=0; /* 頭指針前面的元素小於查找值 */
int j=n-1; /* 尾指針和它後面的元素大於等於查找值 */
int k; /* 中間指針 */
if (n==0) { /* 空列表 */
   *m=0;
   return 0;
}
while (i<j) {
   k=(i+j)/2;
   if (p[k]<value)
    i=k+1;
   else
    j=k;
   op++;
}
/* 頭尾指針指向同一個位置 */
if (p[i]>=value) /* 此位置上元素大於等於查找值 */
   *m=i;
else /* 全部元素都小於查找值 */
   *m=n;
op++;
return op;
}

簡單的排序算法,冒泡,選擇,插入,梳子
==============================================
Latest Snippet Version: 1.01


int selectsort(int p[], int n);
int insertsort(int p[],int n);
int bubblesort(int p[],int n);
int combsort(int p[], int n);

int bubblesort(int p[], int n)
{
int op=0;
int i, j;
int temp;
int flag=1;

for (j=n-1; flag>0 && j>0; j--) {
   flag=0;
   for (i=j; i>0; i--) {
    if (p[i-1]>p[i]) {
     temp=p[i];
     p[i]=p[i-1];
     p[i-1]=temp;
     flag=1;
    }
    op++;
   }
}
return op;
}

int selectsort(int p[], int n)
{
int op=0;
int i, j, max;
int temp;
for (j=n-1; j>0; j--) {
   max=j;
   temp=p[j];
   for(i=j-1; i>=0; i--) {
    if (p[i]>temp) {
     max=i;
     temp=p[i];
    }
    op++;
   }
   p[max]=p[j];
   p[j]=temp;
   op++;
}
return op;
}

int insertsort(int p[],int n)
{
int op=0;
int i,j,temp;
for (j=1; j<n; j++) {
   temp=p[j];
   for(i=j-1; i>=0 && p[i]>temp; i--) {
    p[i+1]=p[i];
    op++;
   }
   p[i+1]=temp;
   op++;
}
return op;
}

/*
* 改進的冒泡排序算法,性能接近堆排序。
* 在 1991 年由 S. Lacey 和 R. Box 發明。
* 據說在特定的重複性輸入下有可能衰退成冒泡排序。
*/
int combsort(int p[], int n)
{
int op=0;
int i;
int temp;
int gap=n;
int flag=1;

while (gap>1 || flag!=0) {
   flag=0;
   gap=(gap==9||gap==10)?11:gap*10/13;
   if (gap==0)
    gap=1;
   for (i=n-1; i-gap>=0; i--) {
    if (p[i-gap]>p[i]) {
     temp=p[i];
     p[i]=p[i-gap];
     p[i-gap]=temp;
     flag=1;
    }
    op++;
   }
}
return op;
}

堆排序算法
====================================
Latest Snippet Version: 1.02


int heapsort(int p[],int n);

/*
* 堆排序算法在 1964 年由 J. Williams 發明。
* 不穩定,不需要輔助空間。
*/
int siftup(int p[],int i,int n);
int insert(int p[], int n);

int heapsort(int p[],int n)
{
int op=0;
int i,temp;

/* 自底向上建造堆 */
for (i=n/2-1; i>=0; i--)
   op+=siftup(p,i,n);

/* 自頂向下建造堆 */
/* for (i=2;i<=n;i++)
*   op+=insert(p,i); */


/* 交換堆頂與堆底的元素,篩選操作把目前處在堆頂的元素
* 插入到變小了堆中,同時從堆中選出新的最大元素到堆頂 */
for (i=n-1; i>0; i--) {
   temp=p[0];
   p[0]=p[i];
   p[i]=temp;
   op++;
   op+=siftup(p,0,i);

}
return op;
}
/*
* 篩選例程
*/
int siftup(int p[],
           int i, /* 堆頂的位置 */
           int n) /* 列表的長度 */
{
int op=0;
int j,temp;

temp=p[i]; /* 要插入的元素已經在根節點位置上,保存它的值 */
/* 要比較的節點位置是當前根節點的左子節,並且它在列表範圍內 */
while ((j=i*2+1)<n) {
   op+=2;
   /* 要比較的左子節點有對應的右子節點,左子節點小於右子節點 */
   if (j+1<n && p[j]<p[j+1])
    j++; /* 要比較的節點位置是當前根節點的右子節點 */
   if (p[j]<=temp) /* 當前做比較的子節點的值小於等於要插入的值 */
    break; /* 停止下移 */
   p[i]=p[j]; /* 做比較的子節點的值上移到當前根節點 */
   i=j; /* 當前根節點下移到做比較的子節點的位置上 */
}
p[i]=temp; /* 插入要插入的值 */
op++;
return op;
}
/*
* 插入例程,把列表的最後一個元素插入到它前面的堆中
*/
int insert(int p[], int n)
{
int op=0;
int i=n-1,j;
int temp;
temp=p[i];
for (; i>0; i=j) {
   op++;
   j=(i-1)/2;
   if (p[j]>=temp)
    break;
   p[i]=p[j];
}
p[i]=temp;
op++;
return op;
}

就地歸併排序算法的未做優化實現
==========================================
Latest Snippet Version: 1.03


int imergesort(int p[], int n);

extern int insertsort(int p[], int n);
extern int binarysearch(int p[],int n, int v, int *m);
static int exchange(int src[],int dest[],int n);
static int swapMergeSort(int p[], int swap[], int n, int flag);
static int swapMerge(int work[], int swap[], int m, int n,int flag);
static int replaceMerge(int p[],int m, int q, int n);
#define IN 1
#define OUT 0

/*
* in-place 歸併排序算法的始作俑者和優化實現請參見:
* http://www.diku.dk/hjemmesider/ansatte/jyrki/Experimentarium/
* 不穩定,不需要輔助空間。餘之實現意圖說明標誌性的方法而未做任何優化。
*/
int imergesort(int p[], int n)
{
int op=0;
int i;
int k=n; /* 在頭部的未排序的元素數目 */
int m=0; /* 在尾部的已排序的元素數目 */

i=k/2;
/* 用列表的前半部分做交換空間,
* 對列表的後半部分做歸併排序。*/
op+=swapMergeSort(&p[n-i],p,i,IN);
m+=i;
k-=i;
while(k>4) {
   i=k/2;
   /* 用未排序子列表的後半部分做交換空間,
   * 對未排序子列表的前半部分做歸併排序*/
   op+=swapMergeSort(p,&p[i],i,IN);
   /* 把新排序出來的子列表與早先排序出來
   * 的子列表做不對稱歸併,它們之間的未
   * 排序空間被置換到列表頭部。*/
   op+=replaceMerge(p,i,n-m,m);
   /* 列表的頭部是未排序的,而尾部是已排序的 */
   m+=i;
   k-=i;
}
/* 最後的剩下的幾個元素直接插入到已排序的列表中 */
op+=insertsort(p,n);
return op; /* 返回操作數 */
}

/*
* 前提:0 -> m-1 和 q -> q+n-1 是兩個有序列表,
* 中間從 m -> q-1 是大小爲 q-m 的未排序的空間。
* 要求 q>=2*m,即中間的未排序空間大於等於左面的列表。
* 結果:歸併出從 q-m 開始的大小是 m+n 的有序列表,
* 0 到 q-m-1 是被置換出來的大小是 q-m 的未排序的空間。
*/
static int replaceMerge(int p[], /* 要歸併的列表即左列表的頭位置 */
        int m, /* 左列表的長度 */
        int q, /* 右列表的頭位置 */
        int n) /* 右列表的長度 */
{
int op=0;
int i=0,j=0,t=0;
int w, r;
int *left=p;
int *right=&p[q];
int *dest=&p[q-m];

while (i<m && j<n) {
   if ((w=(n-j)/(m-i))==0)
    w=1;
   /* 把選擇的左列表元素與右列表的 w 個元素中的最大值做比較 */
   if (left[i]>=right[j+w-1]) {
   /* 選擇的左列表元素大於等於右列表的 m 個元素。*/
    op+=exchange(&right[j],&dest[t],w);
    t+=w;
    j+=w;
   } else {
    /* 以選擇的左列表元素作爲查找值在右列表的 w 個元素中找到小於
    * 查找值的元素個數 */
    op+=binarysearch(&right[j],w,left[i],&r);
    if (r!=0) {
     op+=exchange(&right[j],&dest[t],r);
     t+=r;
     j+=r;
    }
    op+=exchange(&left[i++],&dest[t++],1);
   }
}
if (i<m)
   op+=exchange(&left[i],&dest[t],m-i);

return op;
}
/*
* 交換過程,操作數量是 2*n+1 而不是 3*n,但不保持目標列表的
* 原有次序,故只能用在有序列表與無序列表之間的交換。
*/
static int exchange(int src[],int dest[],int n)
{
int i,temp;

if (n==0)
   return 0;
temp=dest[0];
for(i=0;i<n-1;i++) {
   dest[i]=src[i];
   src[i]=dest[i+1];
}
dest[i]=src[i];
src[i]=temp;

return 2*n+1;
}

static int swapMergeSort(int work[], int swap[], int n, int flag)
{
int op=0;
int temp;

if (n>1) {
   int m=n/2;
   op+=swapMergeSort(work,swap,m,flag^1);
   op+=swapMergeSort(work+m,swap+m,n-m,flag^1);
   op+=swapMerge(work,swap,m,n,flag);
}
else if (flag == OUT) {/* n==1 */
   temp=swap[0];
   swap[0]=work[0];
   work[0]=temp;
}
return op;
}

static int swapMerge(int work[], int swap[], int m, int n, int flag)
{
int *src, *dest;
int i=0, j=m, t=0;
int temp;

if (flag==OUT) {
   src="/work";
   dest=swap;
} else { /* flag==IN */
   src="/swap";
   dest=work;
}

temp=dest[t];
while (i<m && j<n)
   if (src[i] <= src[j]) {
    dest[t++] = src[i];
    src[i++] = dest[t];
   } else {
    dest[t++] = src[j];
    src[j++] = dest[t];
   }
while (i<m) {
   dest[t++] = src[i];
   if (t<n)
    src[i++] = dest[t];
   else
    src[i++] = temp;
}
while (j<n) {
   dest[t++] = src[j];
   if (t<n)
    src[j++] = dest[t];
   else
    src[j++] = temp;
}

return 2*n+1;
}

兩路歸併排序算法
========================================
Latest Snippet Version: 1.04


#i nclude <stdlib.h>
int mergesort(int p[], int n);
extern int insertsort(int p[], int n);
static int merge(int work[], int swap[], int m, int n, int flag);
int mergeSort(int p[], int n);
static int merge_sort(int p[], int swap[], int n, int flag);

/*
* 歸併排序算法在 1938 年由 IBM 發明並在電動整理機上實現。
* 在 1945 年由 J. von Neumann 首次在 EDVAC 計算機上實現。
* 穩定,需要與序列同等大小的輔助空間。這裏實現的是兩路歸併算法。
*/

#define IN 1
#define OUT 0
#define M 8 /* 啓始路段長度 */

int mergesort(int p[], int n)
{
int op=0;
int * work=p;
int * swap;
int i,j,m;
int flag=OUT; /* 對換標誌 */

if (n<=16)
   return insertsort(work,n);
swap=(int*)calloc(n,sizeof(int));
if (swap==NULL)
   return 0;

/* i 是經過插入排序的元素個數和未排序元素的開始位置 */
for(i=0;i+M<=n;i+=M)
   op+=insertsort(work+i,M);
if (i<n)
   op+=insertsort(work+i,n-i);
for(i=M; i<n; i<<=1,flag^=1) { /* i 爲路段長度 */
   m=i<<1; /* m 爲路段長度乘以歸併的路數 */
   /* j 是已經歸併路段的元素個數和未歸併路段元素的開始位置 */
   for(j=0;j+m<=n;j+=m)
    op+=merge(work+j,swap+j,i,m,flag);
   if (j+i<n)
    op+=merge(work+j,swap+j,i,n-j,flag);
   else if (j<n)
    op+=merge(work+j,swap+j,n-j,n-j,flag);
}
if (flag==IN)
   op+=merge(work,swap,n,n,flag);

free(swap);
return op;
}

/*
* 兩路歸併過程。
*/
static int merge(int work[], /* 工作空間,就是要歸併的列表 */
                 int swap[], /* 交換空間,不小於工作空間 */
                 int m, /* 前半部分列表長度和後半部分列表的開始位置 */
                 int n, /* 列表總長度 */
                 int flag) /* 換入換出標誌 */
{
int *src, *dest;
int i=0, j=m, t=0;

if (flag==OUT) {
   src="/work";
   dest=swap;
} else { /* flag==IN */
   src="/swap";
   dest=work;
}

while (i<m && j<n)
   if (src[i] <= src[j])
    dest[t++] = src[i++];
   else
    dest[t++] = src[j++];

while (i<m)
   dest[t++] = src[i++];
while (j<n)
   dest[t++] = src[j++];

return n;
}

/**************************************/
/*   下面是遞歸原型實現,留做參考     */
/**************************************/
int mergeSort(int p[], int n)
{
int op;
int * temp;

temp=(int*)calloc(n,sizeof(int));
if (temp==NULL)
   return 0;
op=merge_sort(p,temp,n,IN);
free(temp);
return op;
}

static int merge_sort(int work[], int swap[], int n, int flag)
{
int op=0;

if (n>1) {
   int m=n/2;
   op+=merge_sort(work,swap,m,flag^1);
   op+=merge_sort(work+m,swap+m,n-m,flag^1);
   op+=merge(work,swap,m,n,flag);
}
else if (flag == OUT) /* n==1 */
   swap[0]=work[0];

return op;
}


快速排序算法
=============================================
Latest Snippet Version: 1.10


int quicksort(int p[],int n);
extern int insertsort(int p[], int n);
static int partition(int p[],int n,int *m);
int quickSort(int p[],int n);
static int quick_sort(int p[],int n);

/*
* 快速排序算法在 1962 年由 C. Hoare 發明。
* 不穩定,需要與 lg(n) 成比例的輔助空間。
*/
static struct stackframe { /* 棧幀 */
int * list;
int length;
};
static struct stackframe sp[64]; /* 棧指針 */
static unsigned int randx; /* 僞隨機數 */
#define M 16

int quicksort(int p[],int n)
{
int op=0;
int i,k;
int *h,l;
int m; /* 基準值的位置 */
struct stackframe *fp; /* 幀指針*/
struct stackframe *stp; /* 棧頂指針 */

if (n<=16)
   return insertsort(p,n);
randx=p[0]%7875;

for (i=0,k=n; k>0; k>>=1,i++); /* i=[lg(n)] */
stp=sp+i;
fp=sp;
fp->list=p;
fp->length=n;
while (fp>=sp) {
   h=fp->list;
   l=fp->length;
   /* 採用 D. Musser 的限定劃分深度的建議 */
   while (l>M && fp<=stp) {
    op+=partition(h,l,&m);
    fp->list=h+m+1;
    fp->length=l-m-1;
    fp++;
    l=m;
   }
   fp--;
}
op+=insertsort(p,n);
return op;
}

/*
* 基準值選擇採用 C. Hoare 建議的隨機選擇策略。
*/
static int partition(int p[],int n,
                     int *m ) /* 返回的基準值的位置 */
{
int i=0; /* 頭指針 */
int j=n-1; /* 尾指針 */
int pivot; /* 基準值 */
int k;
if (n<=1)
   return 0;
randx=(randx*421+1663)%7875; /* 線性同餘僞隨機數 */
k=randx%n;
/* 隨機選擇某個位置的元素作爲基準值並保存它,
* 接着把頭指針指向的元素複製到這個位置上 */
pivot=p[k];
p[k]=p[i];
/* p[i] 已被交換到 p[k],可以覆蓋 */
while (i<j) { /* 頭指針先於尾指針 */
   while (i<j && p[j]>=pivot) /* 尾指針指向的元素大於基準值 */
    j--; /* 前移尾指針 */
   if (i<j)
    p[i++]=p[j]; /* 替換當前p[i]內容爲p[j]的內容, 後移頭指針 */
    /* p[j] 已被交換可以覆蓋 */
   while (i<j && p[i]<=pivot) /* 頭指針指向的元素小於基準值 */
    i++; /* 後移頭指針 */
   if (i<j)
    p[j--]=p[i]; /* 替換當前p[j]內容爲p[i]的內容, 前移尾指針 */
    /* p[i] 已被交換可以覆蓋 */
}
/* 如果最後一次交換的是 p[j],則 i 指針會移動成 i=j */
p[i]=pivot; /* 把保存的基準值保存到當前位置上 */
*m=i; /* 返回基準值當前的位置 */
return n;
}

/**************************************/
/*   下面是遞歸原型實現,留做參考     */
/**************************************/
int quickSort(int p[],int n)
{
if (n<=16)
   return insertsort(p,n);
randx=p[0]%7875;
return quick_sort(p,n);
}

static int quick_sort(int p[],int n)
{
int op=0;
int m;
   
if (n>1) {
   op+=partition(p,n,&m);
   op+=quick_sort(p,m);
   op+=quick_sort(p+m+1,n-m-1);
}
return op;
}

基數排序算法
=================================================
Latest Snippet Version: 1.0


#i nclude <stdlib.h>
int radixsort(int p[], int n);

int distribute(int *src, int *dest, int n, int idx);
/*
* 基數排序算法的最早書面記述在 1923 年由 IBM 發表。當時實
* 現在電動排序機上。在 1954 年由 H. Seward 在計算機上實現。
* 穩定,需要與序列同等大小的輔助空間。
*/
int radixsort(int p[], int n)
{
int * swap;

swap=(int *)calloc(n,sizeof(int));
if (swap==NULL)
   return 0;

/* 如果處理器不是小端字節序,而是大端字節序,
* 則下標應是 3,2,1,0 */
distribute(p, swap, n, 0);
distribute(swap, p, n, 1);
distribute(p, swap, n, 2);
distribute(swap, p, n, 3);

free(swap);
return 4*(2*n+512);
}

#define radix(x,y) (((unsigned char *)&(x))[(y)])
static int count[256];
/*
* 字節分佈例程
*/
int distribute(int *src, int *dest, int n, int idx)
{
int i;
int index[256];
for (i=0; i<256; i++)
   count[i]=0;
/* 統計每個基數的元素數目 */
for (i=0; i<n; i++)
   count[radix(src[i],idx)]++;
/* 計算與每個基數相對應的堆的位置索引 */
for (index[0]=0, i=1; i<256; i++)
   index[i]=index[i-1]+count[i-1];
/* 把源列表中的元素分佈到各個堆中 */
for (i=0; i<n; i++)
   dest[index[radix(src[i],idx)]++]=src[i];

return 2*n+512;
}

AVL 樹數據結構
=================================================
Latest Snippet Version: 1.12


/* avl.h */
/*
* 高度平衡二叉樹的一種重要方案。
* 在 1962 年由 G. Adelson-Velsky 和 E. Landis 發明。
*/
typedef int typekey;
typedef struct avlnode { /* 高度平衡樹節點 */
typekey k; /* 鍵 */
char *v; /* 值 */
int bal;
/* 平衡因子,是節點的右子樹的高度減取左子樹的高度的高度差,
* 當這個高度差爲 -1,0,1 的時候分別是偏左平衡,等高平衡,偏右平衡 */
struct avlnode *left, *right; /* 指向子樹的指針 */
} node, *tree;
extern tree search(typekey, tree);
extern tree insert(typekey, tree);
extern tree delete(typekey, tree);
extern int height(tree);
extern int count(tree);
extern tree deltree(tree);
/* end of avl.h */

/*------------------------------------------------------------------------*/

/* avl.c */
#i nclude <stdlib.h>
#i nclude <stdio.h>
#i nclude "avl.h"

tree search(typekey, tree);
tree insert(typekey, tree);
tree delete(typekey, tree);
int height(tree);
int heightR(tree);
int count(tree);
tree deltree(tree);
static tree insertR(tree);
static tree deleteR(tree);
static tree deltreeR(tree);
static tree lrot(tree);
static tree rrot(tree);
static node* newNode(void);
static void freeNode(node*);
static void Error(void);

static int flag; /* 高度增減標誌 */
static int key; /* 要插入或刪除的鍵 */
static int avl_height = 0; /* avl 樹的高度 */
static tree pool = NULL; /* 節點緩衝池 */
static pool_num = 0; /* 節點緩衝池中節點的當前數目 */
#define POOL_SIZE 1 /* 節點緩衝池中節點的最大數目 */

/*
* 二叉樹查找例程
*/
tree search(typekey key, tree t)
{
while(t != NULL)
   if (t->k > key)
    t = t->left;
   else if (t->k < key)
    t = t->right;
   else
   return t;
return NULL;
}
/*
* 插入例程。
*/
tree insert(typekey k, tree t)
{
key = k;
t = insertR(t);
if (flag == 1)
   avl_height++;
return t;
}
tree insertR(tree t)
{
if (t == NULL){ /* 當前節點爲空 */
   t = newNode(); /* 建立新節點 */
   t->k = key;
   t->left = NULL;
   t->right = NULL;
   t->bal = 0; /* 葉子節點等高平衡 */
   flag = 1; /* 高度增加 */
  return t; /* 無需調整平衡 */
}
else if (t->k < key){
      t->right = insertR(t->right);
      t->bal += flag; /* 右子樹高度可能增加 */
}
else if (t->k > key){
      t->left = insertR(t->left);
      t->bal -= flag; /* 左子樹高度可能增加 */
}
else { /* (t->k == key) 鍵已經存在 */
   Error();
   flag = 0;
}

if (flag == 0) /* 快速結束出口 */
  return t;
/* 左子樹高於右子樹兩層: 需要右旋 */
if(t->bal < -1) {
   /* 當前節點的左子節點偏右平衡 */
   if(t->left->bal > 0)
    /* 使當前節點的左子節點偏左平衡 */    
    t->left = lrot(t->left);
   t = rrot(t);
   flag = 0; /* 本節點的高度不增加 */
}
/* 右子樹高於左子樹兩層: 需要左旋 */
else if(t->bal > 1) {
   /* 當前節點的右子節點左平衡 */
   if(t->right->bal < 0)
    /* 使當前節點的右子節點偏右平衡 */
    t->right = rrot(t->right);
   t = lrot(t);
   flag = 0; /* 本節點的高度不增加 */
}
else if(t->bal == 0)/* 某個子樹增加高度後導致等高平衡 */
   flag = 0; /* 本節點的高度不增加 */
else /* 某個子樹高度增加了,破壞了等高平衡 */
   flag = 1; /* 本節點的高度增加 */
return t;
}
/*
* 刪除例程, 在 1965 年由 C. C. Foster 發明。
*/
tree delete(typekey k, tree t)
{
key = k;
t = deleteR(t);
if (flag == 1)
   avl_height--;
return t;
}
tree deleteR(tree t)
{
tree p;
char * temp;

if(t == NULL) { /* 鍵未找到 */
   Error();
   flag = 0;
}
else if(t->k < key) {
   t->right = deleteR(t->right);
   t->bal -= flag; /* 右子樹高度可能減少 */
}
else if (t->k > key) {
   t->left = deleteR(t->left);
   t->bal += flag; /* 左子樹高度可能減少 */
}
else { /* (t->k == key)鍵找到 */
    /* 有一個子樹爲空 */
   if (t->left == NULL) {
    p = t;
    t = t->right;
    freeNode(p);
    flag = 1; /* 高度減少 */
   return t; /* 無需調整平衡 */
   }
   else if (t->right == NULL) {
    p = t;
    t = t->left;
    freeNode(p);
    flag = 1; /* 有高度變化 */
   return t; /* 無需調整平衡 */
   /* 沒有一個子樹爲空 */
   } else {  
    if(t->bal<0) {
     /* 找到前驅節點 */
     p = t->left;
     while (p->right != NULL)
      p = p->right;
     t->k = p->k;
     temp = t->v;
     t->v = p->v;
     p->v = temp;
     key = p->k;
     t->left = deleteR(t->left);
     t->bal += flag; /* 左子樹高度可能減少 */
    } else {
     /* 找到後繼節點 */
     p = t->right;
     while (p->left != NULL)
      p = p->left;
     t->k = p->k;
     temp = t->v;
     t->v = p->v;
     p->v = temp;
     key = p->k;
     t->right = deleteR(t->right);
     t->bal -= flag; /* 右子樹高度可能減少 */
    }
   }
}  

   if (flag == 0 ) /* 快速結束出口 */
  return t;
/* 左子樹高於右子樹兩層: 需要右旋 */
if(t->bal < -1) {
   /* 當前節點的左子節點偏右平衡 */
   if(t->left->bal > 0) {
    /* 使當前節點的左子節點偏左平衡 */
    t->left = lrot(t->left);
    flag = 1;
   }
   else if (t->left->bal == 0)
    flag = 0;/* 本節點的高度不減少 */
      else
    flag = 1;/* 本節點的高度減少 */
   t = rrot(t);
}
/* 右子樹高於左子樹兩層: 需要左旋 */
else if(t->bal > 1) {
   /* 當前節點的右子節點左平衡 */
   if(t->right->bal < 0) {
    /* 使當前節點的右子節點偏右平衡 */
    t->right = rrot(t->right);
    flag = 1;
   }
   else if (t->right->bal == 0)
    flag = 0;/* 本節點的高度不減少 */
      else
    flag = 1;/* 本節點的高度減少 */
   t = lrot(t);
}
else if (t->bal == 0) /* 某個子樹減少高度後導致等高平衡 */
   flag = 1; /* 本節點的高度減少 */
else /* 某個子樹高度減少了,破壞了等高平衡 */
   flag = 0; /* 本節點的高度不減少 */
return t;
}

/*
* 左旋例程
*            X              Y
*           / /            / /
*          A   Y    ==>   X   C
*             / /        / /
*            B   C      A   B
* 前提:X 偏右不平衡, Y 偏右或等高平衡。
*/
static tree lrot(tree t)
{
tree temp;
int x,y;

temp = t;
t = t->right;
temp->right = t->left;
t->left = temp;
x = temp->bal;
y = t->bal;
/* 旋轉之前:
/* 假定 X 的平衡因子是 x, Y 的平衡因子是 y,
* 設 A 的高度爲 h, 則 Y 的高度爲 h+x
* 節點 B 高度爲 h+x-1-max(y,0);
* 節點 C 的高度爲 h+x-1+min(y,0);
* 旋轉之後:
* 節點 X 的新平衡因子是 x-1-max(y,0);
* 節點 Y 的新平衡因子是 C-(max(A,B)+1) => min(C-A-1,C-B-1)
*     => min(x-2+min(y,0),y-1)
*/
temp->bal = x-1-max(y, 0);
t->bal = min(x-2+min(y, 0), y-1);
return t;
}
/*
* 右旋例程
*            X              Y
*           / /            / /
*          Y   C    ==>   A   X
*         / /                / /
*        A   B              B   C
* 前提:X 偏左不平衡,Y 偏左或等高平衡。
*/
static tree rrot(tree t)
{
tree temp;
int x,y;

temp = t;
t = t->left;
temp->left = t->right;
t->right = temp;
x = temp->bal;
y = t->bal;
/* 旋轉之前:
/* 假定 X 的平衡因子是 x, 節點 Y 的平衡因子是 y,
* 設 C 的高度爲 h, 則 Y 的高度爲 h-x
* 節點 A 高度爲 h-x-1-max(y,0);
* 節點 B 的高度爲 h-x-1+min(y,0);
* 旋轉之後:
* 節點 X 的新平衡因子是 x+1-min(y,0)
* 節點 Y 的新平衡因子是 max(B,C)+1-A => max(B-A+1,C-A+1)
*     => max(y+1,x+2+max(y,0))
*/
temp->bal = x+1-min(y, 0);
t->bal = max(x+2+max(y, 0), y+1);
return t;
}

static void Error(void)
{
printf("/nError: insert or delete key/n");
}
static node* newNode(void)
{
node* p;
if (pool != NULL) {
   p = pool;
   pool = pool->right;
   pool_num--;
}
else
   p=(node*)malloc(sizeof(node));
p->v=NULL;
return p;
}
static void freeNode(node * p)
{

if (p->v != NULL)
   free(p->v);
if (pool_num < POOL_SIZE) {
   p->right = pool;
   pool = p;
   pool_num++;
}
else
   free(p);
}
int height(tree t)
{
return avl_height;
}
int count(tree t)
{
if (t == NULL)
  return 0;
return 1+count(t->left)+count(t->right);
}
tree deltree(tree t)
{
avl_height = 0;
return deltreeR(t);
}
tree deltreeR(tree t)
{
if (t != NULL) {
   t->left = deltreeR(t->left);
   t->right = deltreeR(t->right);
   freeNode(t);
}
return NULL;
}
/* end of avl.c */

傾斜樹數據結構
=======================================
Latest Snippet Version: 1.1


/* splay.h*/
/*
* 自調整二叉樹的一種重要方案。
* 在 1985 年由 D. D. Sleator 和 R. E. Tarjan 發明。
*/
typedef int typekey;
typedef struct node { /* 二叉查找樹節點 */
typekey k; /* 鍵 */
char *v; /* 值 */
struct node *left, *right; /* 指向子樹的指針 */
} node, *tree;

/* 查找例程用宏實現,傾斜例程在要查找的鍵存在的時候把要找的鍵轉移到根節點,
* 查找例程先進行傾斜操作然後判斷根節點是否包含所要的鍵 */
#define search(key,t) ((t)=splay((key),(t),0), ((t)!=NULL&&(t)->k==(key))?(t):NULL)
extern tree splay(typekey, tree, int);
extern tree splayTD(typekey, tree);
extern tree insert(typekey, tree);
extern tree delete(typekey, tree);
extern int height(tree);
extern int count(tree);
extern tree deltree(tree);
/* end of splay.h */

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章