数据结构和算法分析(10)表栈和队列的实际应用
Posted MenAngel
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构和算法分析(10)表栈和队列的实际应用相关的知识,希望对你有一定的参考价值。
本节继续介绍表、栈、队列在编程实践中的应用。
(1)行编辑程序:(允许用户输入出差错,并在发现错误时可以及时更正。)
功能:接受用户从终端输入的字符型的数据,并存入用户的数据区。由于不能保证不出差错,因此“每接受一个字符即存入用户数据区”的做法不是最恰当的;较好的做法是,设立一个输入的缓冲区,用以接受用户输入的一行字符,然后逐行存入用户数据区。
算法原理:当用户发现刚刚键入的一个字符是错的时,可补进一个退格符“#”,以表示前一个字符无效;如果发现当前键入的行内差错较多或者难以补救,则可以键入一个退行符“@”,以表示当前行中的字符均无效。
1 #include <stdio.h> 2 3 #define STACK_SIZE 100 //自定义能够临时存储用户输入的字符数 4 #define STACKINCREMENT 10 5 #define OVERFLOW -2 6 typedef char ElemType; 7 struct StackNode{ 8 ElemType *base; 9 ElemType *top; 10 int stacksize; 11 }; 12 typedef struct StackNode *TempStack; 13 void InitStack(TempStack S,int stackSize); 14 void Push(TempStack S,ElemType e); 15 void Pop(TempStack S,ElemType *e); 16 void DestoryStack(TempStack S); 17 void LineEdit(TempStack S); 18 void ClearStack(TempStack S); 19 20 void InitStack(TempStack S,int stackSize) { 21 S->base = (ElemType *)malloc(stackSize*sizeof(ElemType)); 22 if(!S->base) { 23 printf("内存不足!\\n"); 24 exit(OVERFLOW); 25 } 26 S->top = S->base; 27 S->stacksize = stackSize; 28 } 29 void Push(TempStack S,ElemType e) { 30 //这段话能够使程序有很好的扩容性 31 if((S->top-S->base)>=S->stacksize) { 32 S->base = (ElemType*)realloc(S->base,(S->stacksize+STACKINCREMENT)*sizeof(ElemType)); 33 if(!S->base) { 34 exit(OVERFLOW); 35 } 36 S->top = S->base + S->stacksize; 37 S->stacksize += STACKINCREMENT; 38 } 39 *S->top++ = e; 40 } 41 void Pop(TempStack S,ElemType *e) { 42 if(S->top == S->base) 43 return; 44 *e = *--S->top; 45 } 46 void ClearStack(TempStack S) { 47 S->top = S->base; 48 } 49 void DestoryStack(TempStack S) { 50 S->top = S->base; 51 free(S->base); 52 S->top = NULL; 53 S->base = NULL; 54 } 55 void LineEdit(TempStack S) { 56 ElemType *p,ch,c; 57 InitStack(S, STACK_SIZE); 58 ch = getchar(); 59 while(ch != EOF) { 60 //进行字符入栈操作 61 while(ch!=EOF&&ch!=\'\\n\') { 62 switch(ch) { 63 case \'#\':Pop(S,&c);break; 64 case \'@\':ClearStack(S);break; 65 default:Push(S,ch);break; 66 } 67 ch = getchar(); 68 } 69 Push(S,ch);//最后的回车也要进入临时区 70 //遍历栈中的字符 71 p = S->base; 72 while(p!=S->top) { 73 printf("%c",*p); 74 ++p; 75 } 76 ClearStack(S); 77 if(ch!=EOF) ch = getchar(); 78 } 79 } 80 int main(){ 81 TempStack sq; 82 LineEdit(sq); 83 DestoryStack(sq); 84 return 0; 85 }
一个可调整的地方:
在接受终端输入时,每输入每一行字符(按回车)行编辑程序就自动执行一次,并返回临时栈中所有字符组成的字符串,并再次调用自身,当一行字符为空时程序运行结束。这个程序的缺点在于输出与处理没有分开。
(2)自调整链表:
自调整表如同一个规则的表,但是所有的插入都在表头进行。当一个元素被Find访问时,它就被移到表头而不改变其余项的相对位置。
1)数组实现:
1 /*---------------数组法实现自调整链表---------------*/ 2 #include <stdio.h> 3 #define LIST_SIZE 30 //数组大小 4 typedef char ElemeType; 5 6 struct ListNode{ 7 ElemeType *Array; 8 int num; 9 int Capicity; 10 }; 11 typedef struct ListNode *List; 12 List CreateList(int size){ 13 List list=malloc(sizeof(struct ListNode)); 14 list->Array=malloc(size*sizeof(ElemeType)); 15 list->num=0; 16 list->Capicity=size; 17 return list; 18 } 19 void InitList(List list){ 20 int i; 21 for(i=0;i<26;i++){ 22 list->Array[list->num]=(ElemeType)(\'A\'+list->num); 23 list->num++; 24 } 25 } 26 void printList(List list){ 27 int i; 28 for(i=0;i<list->num;i++){ 29 putchar(list->Array[i]); 30 putchar(\' \'); 31 } 32 } 33 void find(ElemeType ch,List list){ 34 int i; 35 for(i=0;i<list->num;i++){ 36 if(ch==list->Array[i]){ 37 int j; 38 for(j=i;j>0;j--) 39 list->Array[j]=list->Array[j-1]; 40 list->Array[0]=ch; 41 return; 42 } 43 } 44 printf("链表里没有这个元素%c",ch); 45 } 46 int main(){ 47 List list=CreateList(LIST_SIZE); 48 InitList(list); 49 printList(list); 50 ElemeType temp[20]={ 51 \'B\',\'Z\',\'B\',\'C\',\'W\', 52 \'Z\',\'R\',\'E\',\'B\',\'V\', 53 \'E\',\'W\',\'E\',\'T\',\'S\', 54 \'B\',\'C\',\'K\',\'B\',\'C\' 55 };//B出现5次,E、C出现3次,Z出现2次,W出现2次,R、K、T、V、S各一次 56 int i; 57 for(i=0;i<20;i++){ 58 find(temp[i],list); 59 } 60 printf("\\n自调整后的链表是:\\n"); 61 printList(list); 62 printf("\\n"); 63 return 0; 64 }
2)链表实现:
1 /*---------------链表法实现自调整链表---------------*/ 2 #include <stdio.h> 3 typedef char ElemeType; 4 5 struct ElemeNode{ 6 ElemeType element; 7 struct ElemeNode *next; 8 }; 9 typedef struct ElemeNode *PtrToNode; 10 typedef PtrToNode List; 11 List createList(){ 12 List list=malloc(sizeof(struct ElemeNode)); 13 list->next=NULL; 14 return list; 15 } 16 void InsertIntoList(ElemeType temp,List list){ 17 PtrToNode ptr=malloc(sizeof(struct ElemeNode)); 18 ptr->element=temp; 19 ptr->next=list->next; 20 list->next=ptr; 21 } 22 23 InitList(List list){ 24 int i; 25 for(i=25;i>=0;i--){ 26 ElemeType temp=(ElemeType)((int)\'A\'+i); 27 InsertIntoList(temp,list); 28 } 29 } 30 void printList(List list){ 31 PtrToNode ptr=list->next; 32 while(ptr){ 33 putchar(ptr->element); 34 putwchar(\' \'); 35 ptr=ptr->next; 36 } 37 } 38 int DeleteFromList(ElemeType element,List list){ 39 PtrToNode ptr=list; 40 while(ptr->next->element!=element){ 41 ptr=ptr->next; 42 } 43 if(ptr->next==NULL){ 44 return 0;//没有此元素 45 }else{ 46 ptr->next=ptr->next->next; 47 return 1; 48 } 49 } 50 void find(ElemeType element,List list){ 51 if(DeleteFromList(element,list)) 52 InsertIntoList(element,list); 53 else 54 printf("没有此元素!\\n"); 55 } 56 int main(){ 57 List list=createList(); 58 InitList(list); 59 printList(list); 60 ElemeType temp[20]={ 61 \'B\',\'Z\',\'B\',\'C\',\'W\', 62 \'Z\',\'R\',\'E\',\'B\',\'V\', 63 \'E\',\'W\',\'E\',\'T\',\'S\', 64 \'B\',\'C\',\'K\',\'B\',\'C\' 65 };//B出现5次,E、C出现3次,Z出现2次,W出现2次,R、K、T、V、S各一次 66 int i; 67 for(i=0;i<20;i++){ 68 find(temp[i],list); 69 } 70 printf("\\n自调整后的链表是:\\n"); 71 printList(list); 72 printf("\\n"); 73 return 0; 74 }
(3)用一个数组实现多个栈:(除非数组中的每个单元都被使用否则不能有溢出声明)
算法原理:对与不支持指针的语言(例如java)采用游标法实现表:(与这个例子作对比:http://www.cnblogs.com/MenAngel/p/5539085.html)
1 /*---------------游标模式下栈的实现---------------*/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #define SpaceSize 60 5 6 typedef int PtrToNode; 7 typedef PtrToNode Stack; 8 typedef PtrToNode Position; 9 10 struct Node{ 11 int Element; 12 int flag;//记录元素出现的次数 13 Position Next;//Next指针指向的不是具体的结点的首地址,而是结点的下标 14 }; 15 //编译时预先分配的结点数组 16 struct Node CursorSpace[SpaceSize]; 17 //CursorSpace[0]是表头指针 18 static void InitialCursor(void){ 19 int i; 20 for(i=0;i<SpaceSize;i++){ 21 CursorSpace[i].Next=i+1; 22 } 23 CursorSpace[i].Next=0; 24 } 25 26 static Position CursorAlloc(void){ 27 Position p; 28 p=CursorSpace[0].Next; 29 CursorSpace[0].Next=CursorSpace[p].Next; 30 CursorSpace[p].Next=0; 31 return p;//当p的值为0时说明没有空间可用了 32 } 33 34 static void CursorFree(Position p){ 35 CursorSpace[p].Next=CursorSpace[0].Next; 36 CursorSpace[0].Next=p; 37 } 38 void InitStack(Stack *S){ 39 PtrToNode p=CursorAlloc(); 40 //新建的结点需要指向头结点 41 CursorSpace[p].Next=0; 42 *S=p; 43 } 44 45 int IsLast(Position p,Stack S){ 46 return CursorSpace[p].Next==0; 47 } 48 void InsertIntoStack(int x,Stack S){ 49 Position TmpCell; 50 TmpCell=CursorAlloc(); 51 if(TmpCell==0){ 52 printf("空间已经使用完,溢出!\\n"); 53 //exit(0); 54 return; 55 } 56 CursorSpace[TmpCell].Element=x; 57 CursorSpace[TmpCell].flag=1; 58 CursorSpace[TmpCell].Next=CursorSpace[S].Next; 59 CursorSpace[S].Next=TmpCell; 60 } 61 void printStack(Stack stack){ 62 Position p=stack; 63 Position temp; 64 int i; 65 int w=0; 66 while((temp=CursorSpace[p].Next)!=0){ 67 //printf("%d",CursorSpace[temp].flag); 68 for(i=0;i<CursorSpace[temp].flag;i++){ 69 printf("%3d",CursorSpace[temp].Element); 70 w++; 71 if(w%30==0){ 72 printf("\\n"); 73 } 74 } 75 p=CursorSpace[p].Next; 76 } 77 } 78 int main(){ 79 InitialCursor(); 80 Stack stack_a;InitStack(&stack_a); 81 Stack stack_b;InitStack(&stack_b); 82 Stack stack_c;InitStack(&stack_c); 83 Stack stack_d;InitStack(&stack_d); 84 int i; 85 int rand_num; 86 //程序准备的是60个,这里需要4+57=61个空间,一次最后一次操作将会溢出 87 for(i=0;i<=56;i++){ 88 rand_num=rand()%4+1; 89 switch(rand_num){ 90 case 1:InsertIntoStack(i,stack_a);break; 91 case 2:InsertIntoStack(i,stack_b);break; 92 case 3:InsertIntoStack(i,stack_c);break; 93 case 4:InsertIntoStack(i,stack_d);break; 94 default:printf("出现错误\\n"); 95 } 96 } 97 printf("栈a中的元素有:\\n"); 98 printStack(stack_a); 99 printf("\\n栈b中的元素有:\\n"); 100 printStack(stack_b); 101 printf("\\n栈c中的元素有:\\n"); 102 printStack(stack_c); 103 printf("\\n栈d中的元素有:\\n"); 104 printStack(stack_d); 105 printf("\\n"); 106 return 0; 107 }
(4)渡轮模拟问题:(队列的实际应用)
有一个渡口,每条渡船能一次性装载10辆汽车过河,车辆分为客车和货车两类。上渡轮有如下规定:
1.同类车辆先到先上船,客车先于货车上船;
2.每上3辆客车才允许上一辆货车,但若等待的客车不足4辆则用货车填补,反过来,若没有货车等待则用客车填补。
3.装满10辆后则自动开船,当等待时间较长时车辆不足10辆也应认为控制发船。
1)c语言版本:
1 /*---------------队列模拟渡轮问题---------------*/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <string.h> 6 #define YES 1 7 #define NO 0; 8 //采用链表法实现队列 9 struct CarNode{ 10 char name[5];//存车辆的名称 11以上是关于数据结构和算法分析(10)表栈和队列的实际应用的主要内容,如果未能解决你的问题,请参考以下文章