表插入排序

来源:互联网 发布:翻车鱼能吃吗 知乎 编辑:程序博客网 时间:2024/06/14 03:28

上篇文章已经提到直接插入排序中,时间消耗在了元素间的比较次数和移动这两方面。折半插入排序可以减小比较次数,而表插入排序则可以避免元素移动。但它需要建立数据结构,并且需要额外的空间(省时一般都耗空间,这个在算法上很常见哦!)。

首先给出表结构,定义如下:

[cpp] view plaincopy
  1. #define SIZE 100  
  2.   
  3. typedef struct  
  4. {  
  5.     int value;  
  6.     int next;  
  7. }SLNode;  
  8.   
  9. typedef struct  
  10. {  
  11.     SLNode numbers[SIZE];  
  12.     int length;  
  13. }SLinkList;  
其实,表结构就是一个静态链表,它可以用一个数组来初始化,初始化用头元素和第一个元素组成一个循环链表,然后排序时从第二个元素开始插入到这个循环链表中,当然只是修改每个元素的next域。使头结点的next域始终指示最小的那个元素,然后依次向下:每一个元素的next域都指示比它稍大的那个元素。最大的元素的next域指示头结点。这样形成一个循环链表。

当记录下这些信息后,最后一步就是按照next域的指示调整表结构中数组,得到最后的排序结构。下面分三步给出具体的代码:

1、用数组初始化表结构。

2、修改next域形成有序的循环链表。

3、根据next域信息调整表结构中的数组,是数据从小到大排列。

最后再给出一个flash演示,因为文章中不能插入.swf格式的文件,所以我给出链接和文件下载地址。这个动画演示了表插入排序的整个过程。

一:用数组初始化表结构,代码如下:

[cpp] view plaincopy
  1. //参数含义:   
  2. //values:存储数据的整形数组  
  3. //count: 数组的大小  
  4. int InitLink(SLinkList* linkList,int* values,int count)  
  5. {  
  6.     if(count>=SIZE)  
  7.     {  
  8.         printf("超出范围!\n");  
  9.         return 0;  
  10.     }  
  11.     //头节点指示第一个元素,并赋予整形最大值(当然只要赋一个比你要排序的数都大的值就行了)  
  12.     linkList->numbers[0].value = INT_MAX;  
  13.     linkList->numbers[0].next = 1;  
  14.   
  15.     for(int i=1;i<=count;i++)  
  16.     {  
  17.         linkList->numbers[i].value = values[i-1];  
  18.         linkList->numbers[i].next = 0;  
  19.     }  
  20.     linkList->length = count+1;  
  21.     return 1;  
  22. }  

初始化后结构图如下:



( 其中要排序的数组为:int values[LENGTH] = {68,45,23,37,54,12,81,76};  LENGTH 为宏定义是整数 8)

二、修改next域形成有序的循环链表。代码如下:

[cpp] view plaincopy
  1. int Sort(SLinkList* linkList)  
  2. {  
  3.     int len = linkList->length;  
  4.     for(int i=2;i<len;i++)  
  5.     {  
  6.         int q=0;  
  7.         int p = linkList->numbers[0].next;  
  8.         while( linkList->numbers[i].value > linkList->numbers[p].value )  
  9.         {  
  10.             q = p;  
  11.             p = linkList->numbers[p].next;  
  12.         }  
  13.         linkList->numbers[q].next = i;  
  14.         linkList->numbers[i].next = p;  
  15.     }  
  16.     return 1;  
  17. }  

修改next域后如图所示:


每一个元素的next域都指示下一个比它稍大的元素。

三、根据next域调整数组,使数组有序。代码如下:

[cpp] view plaincopy
  1.  // 根据静态链表linkList中各结点的指针值调整记录位置,使得linkList中记录按关键字非递减有序顺序排列  
  2. void Arrange(SLinkList* linkList)   
  3. {  
  4.     SLNode temp;  
  5.     int i,p,q;  
  6.     // p指示第一个记录的当前位置  
  7.     p = linkList->numbers[0].next;    
  8.     for (i=1; i<linkList->length; ++i)   
  9.     {   
  10.         // 第i个记录在linkList中的当前位置应不小于i  
  11.         // 找到第i个记录,并用p指示其在linkList中当前位置  
  12.         while (p<i)   
  13.         {  
  14.             p = linkList->numbers[p].next;  
  15.         }  
  16.         q = linkList->numbers[p].next; // q指示尚未调整的表尾  
  17.         if (p!= i)   
  18.         {  
  19.             temp=linkList->numbers[p];  
  20.             linkList->numbers[p]=linkList->numbers[i];  
  21.             linkList->numbers[i]=temp;  
  22.             // 指向被移走的记录,使得以后可由while循环找回  
  23.             linkList->numbers[i].next=p;   
  24.         }  
  25.          // p指示尚未调整的表尾,为找第i+1个记录作准备  
  26.         p=q;               
  27.     }  
  28. }   

最后调整后结构如下图:

原创粉丝点击