单链表希尔排序算法的一种实现

来源:互联网 发布:cs视频剪辑软件 编辑:程序博客网 时间:2024/05/29 13:57

希尔排序是插入排序的运用,通过逐步缩减步进值,来逐步减少插入排序需要移动元素的次数,从而提高程序运行效率。数组的希尔排序算法可以参考http://blog.csdn.net/huhao_bupt/archive/2009/07/28/4386123.aspx。这里实现了单链表的希尔排序算法。它是在单链表插入排序算法上的延伸。单链表的插入排序算法可以参考http://blog.csdn.net/huhao_bupt/archive/2009/08/12/4438004.aspx

 

这里选取步进值每次以1/2缩小,直到变为1,完成最后一次插入排序。类似插入排序,这里用了三个指针。h1用来遍历链表,找到可以插入的位置。h2用来指向要插入的节点,相当于数组排序里的临时变量。如果没有找到,用一个flag来标记h1移到了h2的位置,此时结束本次遍历,同时移动h2和h3。h3用来指向h2前面的节点。注意防止h2移除链表边界。

 

另外需要注意的是move需要改变指针的位置,所以它的形参是指针的指针,实参是指针的地址。

 

以下是具体代码:

 

#include <stdio.h>
#include <stdlib.h>

 

typedef struct node Node;
struct node
{
 int data;
 Node* next;
};

 

/*创建链表*/
void createlist(Node* head)
{
 Node* p=head;
 int i=1;
 while(i<100)
 {
    p->next=malloc(sizeof(Node));
    p=p->next;
    p->data=rand()%100;
    p->next=NULL;
  i++;
 }
}

 

/*释放链表*/
void freelist(Node* head)
{
 Node* temp=head;
 while(head)
 {
  temp=head;
  head=head->next;
  free(temp);
 }
}

 

/*打印链表*/
void printlist(Node* head)
{
 printf("/n");
 while(head)
 {
  printf("%d ",head->data);
  head=head->next;
 }
 printf("/n");
}

 

/*获取链表中的节点数*/
int getNodeNum(Node* h)
{
 int n=0;
 while(h)
 {
  n++;
  h=h->next;
 }
 return n;
}

 

/*把一个指针移动n步*/
void move(Node** h,int n)
{
 int i;
 for(i=0;i<n;i++)
 {
  *h=(*h)->next;
 }
}


/*单链表希尔排序例程*/
void shellsort(Node* h)
{
     int i=0;
     int flag=0;/*标记一次快速插入迭代是否结束*/
     Node* h1;/*h1用来从头开始遍历寻找插入节点*/
     Node* h2;/*h2用来指向需要插入的结点*/
     Node* h3;/*h3用来指向h2的前一个结点*/
     int n=0;/*节点数*/
     int t;/*步进值*/
     n=getNodeNum(h);/*节点数*/
    
     for(t=n/2;t>0;t=t/2)/*希尔迭代,每次缩小步进值*/
     {
          h2=h3=h;/*每次希尔迭代,初始化h2和h3的位置*/
          move(&h3,t-1);
          move(&h2,t);/*移动t步*/

          while(h2)/*插入排序*/
              {
                    h1=h; /*初始化h1的位置*/
                    flag=0;/*flag置0*/
                    while(flag==0)
                    {
                           if((h1->next->data) > (h2->data))/*如果找到,即把h2所指向的结点插到h1后面,然后跳出循环*/
                           {
                                  h3->next=h2->next;
                                  h2->next=h1->next;
                                  h1->next=h2;
                                  h2=h3->next;/*h2所指节点已经移到前面,h2要向后移动*/
                                  break; /*别忘了此处的break*/
                           }
                           /*移动h1*/
                            for(i=0;i<t;i++)
                            {
                                 h1=h1->next;
                                 if((h1==h2)||(h1==NULL))
                                 {
                                   flag=1;/*h1移到了h2*/
                                   break;/*马上停止移动,防止指针越界*/
                                 }
                            }
                    }
         
                    if((flag==1)&&(h2!=NULL))/*只在h2所指结点不需要前插时,移动h2和h3*/
                    {
                        h2=h2->next;
                        h3=h3->next;
                    }
             }
     }
}


/*单链表插入排序的测试例程*/
int main(void)
{
 int i;
 /*构造一个包含头节点的单链表*/
 Node* head = malloc(sizeof(Node));
 head->data = 0;
 createlist(head);
 printlist(head);
 /*希尔排序*/
 shellsort(head);
 printlist(head);
 freelist(head);
 scanf("%d",&i);
 return 0;
}

原创粉丝点击