C编程思想之抽象数据类型(ADT)(二)

此篇继续前一个博客,以一个火车厢重排问题为例(这里用堆栈形式的缓冲轨),有关此题目,想必大家有所耳闻,我也在网上搜索过,发有大多都是C++版本,而C语言版本只有一版,而且我感觉有点乱,注释少,以至我没有耐心读下去。正好拿这个题目练练手,就当做个大脑体操了,呵呵,步入正题,继续体会抽象数据类型带来的好处。

关于火车厢重排的详细资料,参见下图:

C编程思想之抽象数据类型(ADT)(二)

这里的stack.h,stack.c以及getlib.h等同上篇中的代码。这里只贴出火车厢重排的代码。

  1 /* trainsort.c --- 

  2  * 

  3  * Filename: trainsort.c

  4  * Description: 火车厢重排问题

  5  * Author: magc

  6  * Maintainer: 

  7  * Created: 五  8月 10 13:59:05 2012 (+0800)

  8  * Version: 

  9  * Last-Updated: 五  8月 10 17:37:30 2012 (+0800)

 10  *           By: magc

 11  *     Update #: 217

 12  * URL: 

 13  * Keywords: 

 14  * Compatibility: 

 15  * 

 16  */

 17 

 18 /* Commentary: 

 19  * 题目:假设一列货运列车共有n节编号分别为1~n的车厢,在进站前这n节车厢并不是按其编号有序排列;现要求重新排列各车厢,使该列车在进入车站时,所有车厢从前到后按编号1~n的次序排列,以便各车厢能够停靠在与其编号一致的站点。

 20  * 为了达到这样的效果,可以在一个转轨站里完成车厢的重排工作。在转轨站中有一个入轨,一个出轨和K个位于入轨与出轨间的缓冲铁轨。如下图所示。开始时,具有n节车厢的货车从入轨处进入转轨站;转轨结束时,各车厢从右到左按照编号1~n的次序通过出轨处离开转轨站。

 21  * 

 22  * 

 23  */

 24 

 25 /* Change Log:

 26  * 

 27  * 

 28  */

 29 

 30 /* Code: */

 31 #include <assert.h>

 32 #include <ctype.h>

 33 #include <errno.h>

 34 #include <limits.h>

 35 #include <string.h>

 36 #include <stdarg.h>

 37 #include <stdlib.h>

 38 #include <stdio.h>

 39 #include "../commonlib/genlib.h"

 40 #include "stack.h"

 41 void sort(int trainArray[], int t_len,int buf_num);

 42 int sendout(int outID ,stackADT buf_array[] ,int buf_num);

 43 void hold(int t_index ,stackADT buf_array[],int buf_num);

 44 bool checkout(int outID,stackADT buf_array[] ,int buf_num);

 45 

 46 

 47 int main(int argc, char * argv[])

 48 {

 49     int t_array[8] = { 8,5,3,4,7,6,2,1 };//自定义一个初始的车厢顺序

 50     int buf_num = 3;//假设有三个缓冲轨

 51     sort(t_array,8,buf_num);

 52 

 53     return 0;

 54     

 55 }

 56 /*************************************************************************

 57 *功能描述:火车厢重排

 58 *参数列表:trainArray:初始的火车厢序列数组,t_len:火车厢数量,buf_num:缓冲轨个数

 59 *返回类型:

 60 **************************************************************************/

 61 void sort(int trainArray[], int t_len,int buf_num){

 62     int outID = 1;

 63     int i;

 64     //缓冲轨用堆栈实现,多个缓冲轨用数组来组织,初始都为NULL,在使用时再初始化栈

 65     stackADT buf_array[buf_num];

 66     int m;

 67     for (m = 0; m < buf_num; m++) {

 68         buf_array[m] = NULL;

 69         

 70     }

 71     int t_index;

 72     

 73     //车厢依次从入口进入

 74     for (i = 0; i < t_len; i++) {

 75 

 76         t_index = trainArray[i];

 77         printf("%d号车厢从入口进入\n",t_index);

 78         //每进来一个,例行检查

 79         if(t_index == outID){

 80             outID = sendout(outID , buf_array,buf_num);

 81             continue;

 82         }else{

 83             //            printf("%d车厢寻找缓冲轨\n",trainArray[i]);

 84             hold(t_index,buf_array,buf_num);

 85             

 86             

 87         }

 88     }

 89 }

 90 /*************************************************************************

 91 *功能描述:进入出轨口

 92 *参数列表:outID:当前要进入出轨口的车厢号,buf_array:缓冲轨(堆栈)的数组,buf_num:缓冲轨(堆栈)的个数

 93 *返回类型:返回下一个应该出轨的车号

 94 **************************************************************************/

 95 int sendout(int outID ,stackADT buf_array[] ,int buf_num){

 96     printf("==>%d号车厢进入出轨口\n",outID);

 97     //继续检测下一序号是否符合出轨

 98     outID++;

 99     //每当出去一个车厢后,重新检测缓冲栈中栈顶车厢号,看是否有可进入出轨口的

100     while(checkout(outID,buf_array,buf_num)){

101         outID++;

102     }

103     return outID;

104 }

105 

106 /*************************************************************************

107 *功能描述:检测缓冲轨中是否有应该进入出轨口的

108 *参数列表:outID:当前要进入出轨口的车厢号,buf_array:缓冲轨(堆栈)的数组,buf_num:缓冲轨(堆栈)的个数

109 *返回类型:是否有进入出轨口的车厢(若有,当时已经弹出),主要是后续根据此结果是否需要继续检测下一车厢号

110 **************************************************************************/

111 bool checkout(int outID,stackADT buf_array[] ,int buf_num){

112 

113     int i;

114     printf("在缓冲轨中检查%d号\n",outID);

115     

116     for (i = 0; i < buf_num; i++) {

117         if(buf_array[i] != NULL && outID == StackTop(buf_array[i])){

118             Pop(buf_array[i]);

119             

120             printf("==>%d号车厢进入出轨口\n",outID);

121             return TRUE;

122         }

123     }

124     return FALSE;

125     

126 

127     

128 }

129 /*************************************************************************

130 *功能描述:寻找最优缓冲轨

131 *参数列表:

132 *返回类型:

133 **************************************************************************/

134 void hold(int t_index ,stackADT buf_array[],int buf_num){

135 

136     int i,big = 0;

137     int ok_buf[2] = { -1,-1  };//用此数组来存放最优缓冲轨号和与该栈顶元素小的数组

138     

139     //big用来记录栈顶元素比当前要存放的车号差距

140     for (i = 0; i < buf_num; i++) {

141         if(buf_array[i] != NULL && StackDepth(buf_array[i])>0 && StackTop(buf_array[i])> t_index){

142             big = StackTop(buf_array[i]) - t_index;

143             if(ok_buf[0] == -1){

144                 ok_buf[0] = i;

145                 ok_buf[1] = big;

146             }else if(ok_buf[1] > big){ //当找到与车号差距更小的缓冲轨时,记录来下,备作最优

147                 ok_buf[0] = i;

148                 ok_buf[1] = big;                

149             }

150         }

151     }

152     //当没有找到最优缓冲轨时,放入新的一个缓冲轨中.

153     if(ok_buf[0] == -1 ){

154         //未找到最优缓冲轨

155         int m;

156         for (m = 0; m < buf_num; m++) {

157             if(buf_array[m] == NULL){

158                 buf_array[m] = NewStack();

159                 Push(buf_array[m],t_index);

160                 printf("%d号车厢存放到第%d个缓冲轨中\n",t_index,m);

161                 

162                 return;

163             }

164         }

165         //若未成功放入一个新的缓冲轨时,说明没有足够的缓冲,

166         Error("缓冲轨不足,无法完成重排\n");

167         

168     }else{

169         //已经找到最优缓冲轨

170         Push(buf_array[ok_buf[0]],t_index);

171         printf("%d号车厢存放到第%d个缓冲轨中\n",t_index,ok_buf[0]);

172         return;

173     }

174     

175 }

176 

177 /* trainsort.c ends here */

 

 

CC编译运行:

C编程思想之抽象数据类型(ADT)(二)

若将50行的缓冲轨个数改成2,则出现缓冲不足的情况,无法完成重排,见下图:

C编程思想之抽象数据类型(ADT)(二)

 

小结:
  自从用了堆栈抽象数据类型的定义,使火车厢重排只需要关注自己的业务应用逻辑代码,即使将来有所变动,层次清晰,也很好定位和修改

 

你可能感兴趣的:(数据类型)