个人算法小结(二)

优化排序:

1.希尔排序:

Code:

1.       //理论依据是直接插入排序法  

2.       #include <stdio.h>  

3.       #define N 11  

4.       #define MAXSIZE 100              //最大排序次数   

5.         

6.       typedef struct    

7.       {   

8.           int key;   

9.       }DataType;   

10.   typedef struct  

11.   {   

12.       DataType r[N];   

13.       int length;   

14.   }SqList;   

15.     

16.   void ShellInsert(SqList &L,int dk)//这是一趟希尔插入排序,增量为dk ,对比直接插入增量为1的来理解

17.   {   

18.       int i,j;   

19.       for(i=dk+1;i<=L.length;++i)   

20.       {   

21.           if(L.r[i].key<L.r[i-dk].key)   

22.           {   

23.               L.r[0]=L.r[i];   

24.               for(j=i-dk;j>0&&L.r[0].key<L.r[j].key;j-=dk)   

25.               {   

26.                   L.r[j+dk]=L.r[j];   

27.               }   

28.               L.r[j+dk]=L.r[0];   

29.           }   

30.       }   

31.   }   

32.       

33.   void ShellSort(SqList &L,int dlta[],int t)   

34.   {   

35.       for(int k=0;k<t;++k)   

36.           ShellInsert(L,dlta[k]);   

37.   }   

38.     

39.   int main(void)   

40.   {   

41.       int i,j;   

42.       SqList L;   

43.       L.length=N-1;   

44.       printf("请输入%d个关键字:/n",N-1);   

45.       for(i=1;i<N-1;i++)   

46.       {   

47.           scanf("%d ",&L.r[i].key);   

48.       }   

49.       scanf("%d",&L.r[i].key);   

50.          

51.       int t=1;                             //用来代表排序的趟数       

52.       int dlta[MAXSIZE];                           //增量的数组   

53.       dlta[0]=L.length/2;   

54.     

55.       for(i=1;dlta[i-1]>=2;i++)           //这个for循环用来计算循环的次数和给增量数组赋值,有点难度,想了蛮久   

56.       {   

57.           dlta[i]=dlta[i-1]/2;   

58.           t++;   

59.       }   

60.     

61.       ShellSort(L,dlta,t);   

62.          

63.       for(i=1;i<N-1;i++)   

64.       {   

65.           printf("%d ",L.r[i].key);   

66.       }   

67.       printf("%d/n",L.r[i].key);   

68.       return 0;   

69.   }  

希尔排序是对直接插入排序的改进,它属于插入排序,是个不稳定的排序方法;

思路:先将整个待排序记录序列分割成为若干子序列分别进行直接插入排序,带整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

 

2.快排法:

Code:

1.       /*  

2.       一个acm题:  

3.       Sample Input   

4.       2  

5.       5 898  

6.       3  

7.       3 2 1  

8.       Sample Output   

9.       5 898   

10.   1 2 3   

11.   你应当  O(n*lgn)的算法 避免 Time Limit Exceed   

12.   你应当  scanf 不要使用cin 避免 Time Limit Exceed  

13.   */  

14.   /*  

15.   快速排序的平均时间复杂为O(n*lgn),但是最坏情况(有序)时时间复杂度就变成了O(n*n)了,即此时蜕变成了普通排序。  

16.   故快速排序比较适合杂乱无章的数据排序。  

17.   */ 

18.   #include <stdio.h>  

19.   #include <stdlib.h>   

20.     

21.   int Onefast(int a[],int low,int high)    //优化,取a[0]为辅助空间   

22.   {   

23.       a[0]=a[low];         //这句不能放在while循环句里面  因为low是变化的   

24.       while(low<high)   

25.       {                                

26.           while(low<high&&a[0]<=a[high]) --high;   

27.           a[low]=a[high];      

28.           while(low<high&&a[0]>=a[low]) ++low;   

29.           a[high]=a[low];   

30.       }   

31.       a[low]=a[0];   

32.       return low;    //关键步骤:返回此时下标所在的位置   

33.   }   

34.     

35.   void Fastsort(int a[],int low,int high)   

36.   {   

37.       int loc;   //定义一个变量用来记录每趟快排后返回的位置   

38.       if(low<high)                  //递归一定是有出口的   

39.       {   

40.           loc=Onefast(a,low,high);   //每次返回的low值得以保存

41.           Fastsort(a,low,loc-1);   

42.           Fastsort(a,loc+1,high);   

43.       }   

44.   }   

45.   int main(void)   

46.   {   

47.       int i,n;   

48.       int *a;   

49.       while(scanf("%d",&n)!=EOF)   

50.       {   

51.           n=n+1;   

52.           a=(int *)malloc(sizeof(int)*n);   

53.           for(i=1;i<n-1;i++)   

54.           {   

55.               scanf("%d ",&a[i]);   

56.           }   

57.           scanf("%d",&a[i]);   

58.           Fastsort(a,1,n-1);   

59.           for(i=1;i<n-1;i++)   

60.           {   

61.               printf("%d ",a[i]);   

62.           }   

63.           printf("%d/n",a[i]);   

64.       }   

65.       return 0;   

66.   }   

快排法是我接触的比较早的一个排序算法,是对冒泡排序的一种改进,使时间复杂度降低了。快排法是一种数据频繁跳跃“交换”---程序中优化成移动 的排序方法,所以是一种不稳定的排序。且快排法适合用于完全无序的关键字排序,对于有序的关键字,快排效率降低成普通排序。

 

3.堆排法:

Code:

1.       #include <stdio.h>  

2.       #define MAX 101      //最大关键字系列长度为100   

3.         

4.       typedef struct    

5.       {   

6.           int key;   

7.       }DataType;   

8.       typedef struct  

9.       {   

10.       DataType r[MAX];   

11.       int length;   

12.   }SqList;   

13.     

14.   typedef SqList HeapType;   

15.     

16.   void HeapAdjust(HeapType &H,int s,int m)          //创建初始大顶堆,s为第一个下标,m为最后一个下标   

17.   {   

18.       int j;   

19.       H.r[0]=H.r[s];   

20.       for(j=2*s;j<=m;j*=2)   

21.       {   

22.           if(j<m&&H.r[j].key<H.r[j+1].key)            //确保j为较大孩子的下标   

23.           {   

24.               ++j;   

25.           }   

26.           if(!(H.r[0].key<H.r[j].key))   //这里j必定为大孩子的下标

27.               break;   

28.           H.r[s]=H.r[j];   

29.           s=j;   

30.       }   

31.       H.r[s]=H.r[0];   

32.   }   

33.     

34.   void HeapSort(HeapType &H)                   //堆排序过程   

35.   {   

36.       int i;   

37.       for(i=H.length/2;i>0;--i)      //这个for循环的作用是构建初始大顶堆,从第H.length/2个有叶子的结点开始   

38.           HeapAdjust(H,i,H.length);   

39.       for(i=H.length;i>1;--i)         //这个for循环用来进行堆排序,i从最后一个数开始(由于我没用零的下标,所以可以取到H.length下标的数)   

40.       {   

41.           H.r[0]=H.r[1];   

42.           H.r[1]=H.r[i];   

43.           H.r[i]=H.r[0];   

44.           HeapAdjust(H,1,i-1);       //排序从第一个开始而不是0(用做辅助空间)   

45.       }   

46.   }   

47.     

48.   int main(void)   

49.   {   

50.       int n;   

51.       HeapType L;   

52.       printf("请输入关键字序列的长度:");   

53.       scanf("%d",&n);   

54.       L.length=n;       //L.r[0]用来做辅助空间,其实是申请了n+1个空间   

55.       printf("请输入%d个关键字:",L.length);   

56.       for(int i=1;i<L.length;i++)   

57.       {   

58.           scanf("%d ",&L.r[i].key);   

59.       }   

60.       scanf("%d",&L.r[i].key);   

61.       HeapSort(L);   

62.       printf("排序后的关键字序列:/n");   

63.       for(i=1;i<L.length;i++)   

64.       {   

65.           printf("%d ",L.r[i].key);   

66.       }   

67.       printf("%d/n",L.r[i].key);   

68.       return 0;   

69.   }  

每执行一趟堆排法之后,就将堆顶“最大”的数放到了有序区中,所以用大顶堆进行堆排法后得到的关键字序列将是升序的;堆排法在最坏的情况下,其时间复杂度也为On*logn,且仅需一个记录大小供交换的辅助存储空间。也是个不稳定的排序方法。对于n较大的文件比较有效。

 

4.归并排序:

Code:

1.       #include <stdio.h>  

2.       #include <stdlib.h>  

3.       #define MAX 50    //最大序列长度   

4.       typedef struct    

5.       {   

6.           int key;   

7.       }RcdType;   

8.         

9.       typedef struct  

10.   {   

11.       RcdType r[MAX];   

12.       int length;   

13.   }SqList;   

14.     

15.   void Merge(RcdType SR[],RcdType TR[],int i,int m,int n)    //归并

16.    //这里不能写成&TR[],否则编译通不过(数据类型不一直),有待探讨   

17.   {//将有序的SR[i..m]SR[m+1..n]归并为有序的TR[i..n]   

18.       for(int j=m+1,k=i;i<=m&&j<=n;k++)   

19.       {   

20.           if(SR[i].key<SR[j].key)   

21.               TR[k].key=SR[i++].key;   

22.           else    

23.               TR[k].key=SR[j++].key;   

24.       }   

25.       if(i<=m)   

26.       {   

27.           for(;i<=m;i++,k++)         //i,j,k的初始值是链接到上面的   

28.               TR[k].key=SR[i].key;   

29.       }   

30.       if(j<=n)   

31.       {   

32.           for(;j<=n;j++,k++)   

33.               TR[k].key=SR[j].key;   

34.       }   

35.   }   

36.     

37.     

38.   void MSort(RcdType SR[],RcdType TR1[],int s,int t) //这里不能写成&TR1[],否则编译通不过,讨论为什么   

39.   {//SR[s...t]归并为TR1[s..t]   

40.     

41.       int m;   

42.       RcdType *TR2;   

43.       TR2=(RcdType *)malloc(sizeof(RcdType)*(t-s+1));        //建立一个临时数组做辅助空间   

44.       if(s==t)               //出口   

45.           TR1[s].key=SR[s].key;   

46.       else    

47.       {   

48.           m=(s+t)/2;   

49.           MSort(SR,TR2,s,m);      //递归思想

50.           MSort(SR,TR2,m+1,t);   

51.           Merge(TR2,TR1,s,m,t);   

52.       }   

53.   }   

54.     

55.     

56.   int main(void)   

57.   {   

58.       SqList L;   

59.       printf("请输入你要创建的关键字序列的长度:");   

60.       scanf("%d",&L.length);   

61.       printf("请输入%d个数:/n",L.length);   

62.     

63.       for(int i=1;i<L.length;i++)   

64.       {   

65.           scanf("%d ",&L.r[i].key);   

66.       }   

67.       scanf("%d",&L.r[i].key);   

68.     

69.       MSort(L.r,L.r,1,L.length);    

70.     

71.       printf("排序后:/n");   

72.       for(i=1;i<L.length;i++)   

73.       {   

74.           printf("%d ",L.r[i].key);   

75.       }   

76.       printf("%d/n",L.r[i].key);   

77.       return 0;   

78.   }  

2-路归并排序的核心操作是将数组中前后相邻的两个有序序列归并为一个有序序列。以前合并两个有序链表时用的方法其实就是这个思想。归并排序是一个有序的排序方法,但一般情况下,很少利用2-路归并排序法进行内部排序,一般用于外部排序。

 

5.基数排序

Code:

1.       #include <stdio.h>  

2.       #include <stdlib.h>   

3.         

4.       /队列部分  

5.       #define OVERFLOW -2  

6.       #define ERROR  0;    

7.       typedef  int QElemType;    

8.         

9.       typedef struct QNode   

10.   {   

11.       QElemType data;   

12.       struct QNode *next;   

13.   }QNode,*QueuePtr;   

14.     

15.   typedef struct  

16.   {   

17.       QueuePtr front;   

18.       QueuePtr rear;   

19.   }LinkQueue;   

20.     

21.     

22.     

23.   //初始化   

24.   int InitQueue(LinkQueue &Q)   

25.   {   

26.       Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));   

27.       if(!Q.front)exit(OVERFLOW);   

28.       Q.front->next=NULL;   

29.       return 1;   

30.   }   

31.     

32.   int QueueEmpty(LinkQueue Q)   

33.   {   

34.       if(Q.front==Q.rear)     //不要写成赋值符号   

35.           return 1;         //空队列返回1,队列非空返回0   

36.       else    

37.           return 0;   

38.   }   

39.     

40.     

41.   //销毁队列   

42.   int DestroyQueue(LinkQueue &Q)   

43.   {   

44.       while(Q.front)   

45.       {   

46.           Q.rear=Q.front->next;   

47.           free(Q.front);   

48.           Q.front=Q.rear;   

49.       }   

50.       return 1;   

51.   }   

52.     

53.     

54.     

55.   //从对头删除元素并用e返回其值   

56.   int DeQueue(LinkQueue &Q,QElemType &e)   

57.   {   

58.       QNode *p;   

59.       p=(QueuePtr)malloc(sizeof(QNode));   

60.       if(Q.front==Q.rear) return ERROR;    //我汗   以前写的都将==写成了=    无语   

61.       p=Q.front->next;   

62.       e=p->data;   

63.       Q.front->next=p->next;   

64.       if(Q.rear==p)Q.rear=Q.front;    //还是等号与赋值符号的问题,这个是我易错点  千万要小心   

65.       free(p);   

66.       return 1;   

67.   }   

68.     

69.   //从对尾插入元素   

70.   int EnQueue(LinkQueue &Q,QElemType e)   

71.   {   

72.       QueuePtr p;   

73.       p=(QueuePtr)malloc(sizeof(QNode));   

74.       if(!p)exit(OVERFLOW);   

75.       p->data=e;   

76.       p->next=NULL;   

77.       Q.rear->next=p;   

78.       Q.rear=p;   

79.       return 1;   

80.   }   

81.     

82.   //   基数排序部分  

83.   #define N 8     //关键字个数   

84.   typedef int KeyType;   

85.   typedef struct  

86.   {   

87.       KeyType key;   

88.   }DataType;   

89.     

90.     

91.   int digit(KeyType key,int m,int r)   

92.   {   

93.       int i,d;   

94.       if(m==0)                //从第0位开始的   

95.           return key%r;   

96.       d=r;   

97.       for(i=1;i<m;i++)   

98.           d*=r;   

99.       return ((int)(key/d)%r);   

100.    }   

101.      

102.    void RadixSort(DataType L[],int n,int m,int r)   

103.    {//L中的关键字为mr进制数,L的长度为n                                                                                                  

104.        LinkQueue *q;   

105.        int i,j,k;   

106.        q=(LinkQueue *)malloc(r*sizeof(LinkQueue));   

107.        for(i=0;i<r;i++)   

108.            InitQueue(q[i]);   

109.        for(i=0;i<m;i++)   

110.        {   

111.            for(j=0;j<n;j++)   

112.            { //L[j].key的第i位数赋给kk等于几就将L[j].key入对应q[k]的队列,按号入座   

113.                k=digit(L[j].key,i,r);      //个人认为这步最关键

114.                EnQueue(q[k],L[j].key);   

115.            }   

116.            k=0;   

117.      

118.            for(j=0;j<r;j++)   

119.            {   

120.                for(;!QueueEmpty(q[j]);k++)   

121.                    DeQueue(q[j],(L[k].key));   

122.            }   

123.            if(i!=m-1)   

124.            {   

125.                for(j=0;j<n-1;j++)   

126.                    printf("%d/t",L[j].key);   

127.                printf("%d/n/n",L[j].key);   

128.            }   

129.        }   

130.        printf("经过%d次基数排序后已有序如下:/n",m);   

131.        for(j=0;j<n-1;j++)   

132.            printf("%d/t",L[j].key);   

133.        printf("%d/n/n",L[j].key);   

134.        for(i=0;i<r;i++)   

135.            DestroyQueue(q[i]);   

136.    }   

137.      

138.    int main(void)   

139.    {   

140.        int m=3;    //默认关键字最长位为四位   

141.        printf("请限定你要输入关键子的最长位数为:");   

142.        scanf("%d",&m);   

143.        DataType *L;   

144.        L=(DataType *)malloc(sizeof(DataType)*N);   

145.        printf("请输入%d个最长位数为%d关键字序列:/n",N,m);   

146.        fflush(stdin);   

147.        for(int i=0;i<N-1;i++)   

148.        {   

149.            scanf("%d ",&L[i].key);   

150.        }   

151.        scanf("%d",&L[i].key);   

152.        RadixSort(L,N,m,10);   

153.        return 0;   

154.    }   

155.      

算法思想:

1.设置r个队列,队列编号分别为012…,r-1;

2.按数据元素关键字最低位上的数字值一次把n个数据元素分配到这r个队列中(入队列);

3.按照队列编号从小到大排序,将队列中的数据元素收集起来,形成一个新的数据元素序列,这两步就是第一趟基数排序;

4. 接着对第一趟基数排序后得到的数据元素序列,再按照数据元素关键字的次低位上的数字进行第二趟基数排序;

5. 如此反复,经过m趟基数排序后,就得到了数据元素的有序序列。

注:r是指进制数;m是值关键字位数的最大值。

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值