数据结构
一、顺序表的基本操作
1 实验一:顺序表的基本操作。 2 3 编写一个完整的程序,实现顺序表的建立、插入、删除、输出等基本运算。 4 (1) 建立一个顺序表,含有n个数据元素。 5 (2) 输出顺序表及顺序表的长度。 6 (3) 在顺序表中删除值为x的结点或者删除给定位置i的结点。 7 (4) 将顺序表就地逆置,即利用原表的存储空间将线性表(a1,a2,...,an)逆置为(an,an-1,...,a1)。 8 (5) 将顺序表按升序排序。 9 (6) 设顺序表中的数据元素递增有序,将x插入到顺序表的适当位置上,以保持该表的有序性。 10 (7) 将两个顺序有序表A和B合并为一个有序表C。 11 (8) 在主函数中设计一个简单的菜单,分别测试上述算法。 12 13 #include<stdio.h> 14 #include<stdlib.h> 15 16 #define LIST_INIT_SIZE 100 17 #define LISTINCREMENT 10 18 #define OK 1 19 #define OVERFLOW -2 20 #define ERROR 0 21 22 typedef int ElemType; 23 24 typedef struct{ 25 ElemType *elem; 26 int length; 27 int listsize; 28 }SqList; 29 30 int cmp(const void *a,const void *b) 31 { 32 return *(int*)a-*(int*)b; 33 } 34 35 36 //创建一个空表 37 int InitList(SqList &L) 38 { 39 L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));//分配空间 40 if(!L.elem) 41 return OVERFLOW; 42 L.length=0; 43 L.listsize=LIST_INIT_SIZE; 44 return OK; 45 } 46 47 //在创建的空表中插入数据 48 int ListInsert(SqList &L,int i,ElemType e) 49 { 50 ElemType* newbase; 51 //ElemType* q; 52 if(i<0 || i>L.length+1) 53 return ERROR; 54 if(L.length>=L.listsize)//当前空间已满,增加新空间 55 { 56 newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType)); 57 if(!newbase) 58 return OVERFLOW; 59 L.elem=newbase; 60 L.listsize+=LISTINCREMENT; 61 } 62 63 L.elem[i]=e; 64 //printf("%d ",L.elem[i]); 65 L.length++; 66 return OK; 67 } 68 69 //删除位置为i的节点 70 int ListDelete(SqList &L,int i) 71 { 72 ElemType* p; 73 ElemType* q; 74 if(i<0 || i>L.length) 75 return ERROR; 76 p=&(L.elem[i-1]); 77 //e=*p; 78 q=L.elem+L.length-1; 79 for(++p;p<=q;p++) 80 *(p-1)=*p; 81 L.length--; 82 return OK; 83 } 84 85 //在顺序表中删除数据x 86 int DeleteX(SqList &L, int x) 87 { 88 ElemType* p; 89 90 int i; 91 for(i=0;i<L.length;i++) 92 if(L.elem[i]==x) 93 { 94 break; 95 } 96 p=&L.elem[i]; 97 //free(p); 98 for(int j=i;j<L.length-1;j++) 99 { 100 L.elem[j]=L.elem[j+1]; 101 } 102 L.length--; 103 return OK; 104 } 105 106 //反转顺序表 107 int TurnArrond(SqList &L)//翻转顺序表 108 { 109 ElemType* p; 110 ElemType* q; 111 int t; 112 p=&(L.elem[0]); 113 q=L.elem+L.length-1; 114 for(p;p<q;p++,q--) 115 { 116 t=*q; 117 *q=*p; 118 *p=t; 119 } 120 return OK; 121 } 122 123 //升序排列顺序表 124 int ABC(SqList &L) 125 { 126 int a[10000]; 127 int i; 128 for(i=0;i<L.length;i++) 129 a[i]=L.elem[i]; 130 131 qsort(a,L.length,sizeof(a[0]),cmp); 132 133 for(i=0;i<L.length;i++) 134 L.elem[i]=a[i]; 135 return OK; 136 } 137 138 //把顺序表升序排列后插入元素e 139 int ListInsertABC(SqList &L,ElemType e) 140 { 141 ElemType* newbase; 142 int i,j; 143 if(L.length+1>=L.listsize)//当前空间已满,增加新空间 144 { 145 newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType)); 146 if(!newbase) 147 return OVERFLOW; 148 L.elem=newbase; 149 L.listsize+=LISTINCREMENT; 150 } 151 152 for(i=0;i<L.length;i++) 153 if(e<L.elem[i]) 154 break; 155 156 for(j=L.length;j>i;j--) 157 { 158 L.elem[j]=L.elem[j-1]; 159 } 160 L.length++; 161 L.elem[j]=e; 162 //printf("%d ",L.elem[i]); 163 return OK; 164 } 165 166 //合并顺序表L,L1为L2 167 int MergeList(SqList L,SqList L1,SqList &L2) 168 { 169 ElemType* pa; 170 ElemType* pb; 171 ElemType* pc; 172 ElemType* pa_last; 173 ElemType* pb_last; 174 pa=L.elem; 175 pb=L1.elem; 176 // L2.elem=pc; 177 L2.listsize=L.listsize+L1.listsize; 178 pc=L.elem=(ElemType*)malloc(L2.listsize * sizeof(ElemType)); 179 180 pa_last=L.elem+L.length-1; 181 pb_last=L1.elem+L1.length-1; 182 while(pa<=pa_last && pb<=pb_last) 183 { 184 if(*pa<=*pb) 185 *pc++=*pa++; 186 else 187 *pc++=*pb++; 188 } 189 while(pa<=pa_last) 190 *pc++=*pa++; 191 while(pb<=pb_last) 192 *pc++=*pb++; 193 194 for(int i=0;i<L2.length;i++) 195 printf("%d ",L2.elem[i]); 196 return OK; 197 } 198 199 //打印菜单 200 void printScreen() 201 { 202 //printf("1.建立一个顺序表,含有n个数据元素。 "); 203 printf("1.输出顺序表L1及其长度 "); 204 printf("2.删除给定位置i的结点 "); 205 printf("3.在顺序表中删除值为x的结点 "); 206 printf("4.逆置顺序表 "); 207 printf("5.将顺序表按升序排序 "); 208 printf("6.设顺序表中的数据元素递增有序,将x插入到顺序表的适当位置上,以保持该表的有序性 "); 209 printf("7.将两个顺序有序表L和L1合并为一个有序表L2 "); 210 printf("0.退出操作系统。 "); 211 printf("请输入需要的操作序号:"); 212 } 213 214 //输出顺序表L 215 void printSqList(SqList &L) 216 { 217 int i; 218 for(i=0;i<L.length;i++) 219 printf("%d ",L.elem[i]); 220 printf(" "); 221 } 222 223 int main() 224 { 225 SqList L,L1,L2; 226 InitList(L); 227 InitList(L1); 228 InitList(L2); 229 int n,e,muse,i,x; 230 bool flag; 231 //建立第一个的顺序表 232 printf("请输入第一个数据表的长度:"); 233 scanf("%d",&n); 234 printf("请以次输入长度为%d的顺序表:",n); 235 for(i=0;i<n;i++) 236 { 237 scanf("%d",&e); 238 ListInsert(L,i,e);//依次在第i个位置插入顺序表 239 } 240 printf("第一个顺序表的次序为:"); 241 printSqList(L); 242 243 //建立第二个顺序表 244 printf("建立第二个顺序表,请输入要第二个建立数据表的长度:"); 245 scanf("%d",&n); 246 printf("请以次输入长度为%d的顺序表:",n); 247 for(i=0;i<n;i++) 248 { 249 scanf("%d",&e); 250 ListInsert(L1,i,e);//依次在第i个位置插入顺序表 251 } 252 printf("第二个顺序表的次序为:"); 253 printSqList(L1); 254 255 //打印菜单 256 printScreen(); 257 scanf("%d",&muse); 258 flag=true; 259 while(1) 260 { 261 switch(muse) 262 { 263 case 0: 264 flag=false; 265 break; 266 case 1: 267 printf("顺序表的长度为:"); 268 printf("%d ",L.length); 269 break; 270 case 2: 271 printf("请输入要删除的节点:"); 272 scanf("%d",&i);//删除顺序表的节点 273 if(ListDelete(L,i)) 274 { 275 printf("删除成功! "); 276 printSqList(L); 277 } 278 else 279 printf("删除失败! "); 280 break; 281 case 3: 282 printf("请输入要删除的节点x的值:"); 283 scanf("%d",&x); 284 if(DeleteX(L,x)) 285 { 286 printf("删除成功! 顺序表为:"); 287 printSqList(L); 288 } 289 else 290 printf("删除失败! "); 291 break; 292 case 4: 293 //逆序顺序表 294 if(TurnArrond(L)) 295 { 296 printf("逆序成功! "); 297 printf("顺序表的次序为:"); 298 printSqList(L); 299 } 300 else 301 printf("逆序失败! "); 302 break; 303 case 5: 304 //顺序表升序排列 305 if(ABC(L)) 306 { 307 printf("顺序表升序排列成功! "); 308 printf("顺序表的次序为:"); 309 printSqList(L); 310 } 311 else 312 printf("顺序表升序排列失败! "); 313 314 printf("请输入要插入的数据:"); 315 scanf("%d",&e); 316 if(ListInsertABC(L,e)) 317 { 318 printf("顺序插入成功! "); 319 printf("顺序表的次序为:"); 320 printSqList(L); 321 } 322 323 else 324 printf("顺序插入失败! "); 325 break; 326 case 6: 327 ABC(L); 328 printf("请输入要插入的数字x的值:"); 329 scanf("%d",&x); 330 if(ListInsertABC(L,x)) 331 { 332 printf("操作成功! "); 333 printf("顺序表的次序为:"); 334 printSqList(L); 335 } 336 else printf("操作失败! "); 337 break; 338 case 7: 339 if(MergeList(L,L1,L2)) 340 { 341 printf("顺序表L,L1合并成功! "); 342 //printf("顺序表的次序为:"); 343 //printSqList(L2); 344 } 345 else 346 printf("顺序表合并失败! "); 347 break; 348 default: 349 break; 350 } 351 if(!flag) 352 break; 353 printf(" 请输入你要的下一步操作序号:"); 354 scanf("%d",&muse); 355 } 356 357 358 if(L.elem) 359 free(L.elem); 360 if(L1.elem) 361 free(L1.elem); 362 if(L2.elem) 363 free(L2.elem); 364 365 366 return 0; 367 }
二、单链表的基本操作
1 实验二:单链表的基本操作 2 3 编写一个完整的程序,实现单链表的建立、插入、删除、输出等基本操作。 4 (1)建立一个带头结点的单链表。 5 (2)计算单链表的长度,然后输出单链表。 6 (3)查找值为x的直接前驱结点q。 7 (4)删除值为x的结点。 8 (5)把单向链表中元素逆置(不允许申请新的结点空间)。 9 (6)已知单链表中元素递增有序,请写出一个高效的算法,删除表中所有值大于mink且小于maxk的元素(若表中存在这样的元素),同时释放被删结点空间,并分析你的算法的时间复杂度(注意:mink和maxk是给定的两个参变量,他们的值可以和表中的元素相同,也可以不同)。 10 (7)同(6)的条件,试写一高效的算法,删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同),同时释放被删结点空间,并分析你的算法时间复杂度。 11 (8)利用(1)建立的链表,实现将其分解成两个链表,其中一个全部为奇数,另一个全部为偶数(尽量利用已知的存储空间)。 12 (9)在主函数中设计一个简单的菜单,分别测试上述算法。 13 14 # include <stdio.h> 15 # include <stdlib.h> 16 17 typedef struct node 18 { 19 int data; 20 struct node * next; 21 }Lnode, * LinkList; //LinkList的数据类型是struct node *; 22 23 int m=sizeof(Lnode); //Lnode结构体变量,结点变量; 24 25 //建立新的链表 26 void Bulid_List(LinkList root) 27 { 28 int num; 29 LinkList s,p; //定义了两个结构体指针变量; 30 s=root->next; //root->next和s同时指向第一个结点; 31 int n; 32 printf("请输入新建链表的长度n数据: "); 33 scanf("%d",&n); 34 printf("请依次建立链表:"); 35 for(int i=0;i<n;i++) 36 { 37 scanf("%d",&num); 38 s->data=num; 39 p=(LinkList)malloc(m); //动态分配内存空间 40 s->next=p; 41 s=p; 42 s->next=NULL; 43 } 44 printf("链表已建立! "); 45 } 46 47 //对链表的输出,包括长度和元素 48 void OutPut_list(LinkList root) 49 { 50 int len=0; 51 LinkList s; 52 s=root->next; 53 if(s->next==NULL) 54 printf("单链表无数据,请先新建单链表。 "); 55 else 56 { 57 while(s->next!=NULL) 58 { 59 s=s->next; 60 len++; 61 } 62 printf("单链表的长度为:%d ",len); 63 printf("单链表的数据如下: "); 64 s=root->next; 65 while(s->next!=NULL) 66 { 67 printf("%d ",s->data); 68 s=s->next; 69 } 70 printf(" "); 71 } 72 } 73 74 //查询元素 75 void Find_list(LinkList root,int x) 76 { 77 LinkList s,p; 78 if(root->next->next==NULL) 79 printf("单链表无数据,请先新建单链表。 "); 80 else 81 { 82 s=root->next; 83 p=root->next->next; 84 if(s->data==x) 85 printf("此X值无前驱结点。 "); 86 else 87 { 88 while(p->next!=NULL) 89 { 90 if(p->data==x) 91 { 92 printf("此X值的前驱结点的值为:%d ",s->data); 93 return; 94 } 95 else 96 { 97 s=p; 98 p=p->next; 99 } 100 } 101 printf("此链表不存在值为X的结点。 "); 102 } 103 } 104 return; 105 } 106 107 //删除元素 108 void Delete_list(LinkList root,int x) 109 { 110 LinkList s; 111 int flag; 112 if(root->next->next==NULL) 113 printf("单链表无数据,请先新建单链表。 "); 114 else 115 { 116 flag=0; 117 while(root->next!=NULL) 118 { 119 if(root->next->data==x) 120 { 121 if(root->next->next!=NULL) 122 { 123 s=root->next; 124 root->next=root->next->next; 125 free(s); 126 flag=1; 127 return; 128 } 129 } 130 else 131 root=root->next; 132 } 133 if(flag==0) 134 printf("待删除的数据不存在。 "); 135 } 136 return; 137 } 138 139 LinkList NEW() 140 { 141 LinkList new_node; 142 new_node=(LinkList)malloc(m); 143 new_node->next=NULL; 144 new_node->data=0; 145 return new_node; 146 } 147 148 //分解链表 149 void Divid(LinkList head) 150 { 151 LinkList head_odd,head_even,p_odd,p_even,p,s; 152 head_odd=NEW(); 153 head_even=NEW(); 154 p=head->next; 155 p_odd=head_odd; 156 p_even=head_even; 157 while(p!=NULL) 158 { 159 s=p; 160 p=p->next; 161 if(s->data%2==0) 162 { 163 p_odd->next=s; 164 p_odd=p_odd->next; 165 p_odd->next=NULL; 166 } 167 else 168 { 169 p_even->next=s; 170 p_even=p_even->next; 171 p_even->next=NULL; 172 } 173 } 174 printf("构建成功! "); 175 printf("奇数链表为:"); 176 p=head_even->next; 177 while(p->next!=NULL) 178 { 179 printf("%d ",p->data); 180 p=p->next; 181 } 182 printf(" 偶数链表为:"); 183 p=head_odd; 184 while(p->next!=NULL) 185 { 186 printf("%d ",p->next->data); 187 p=p->next; 188 } 189 printf(" "); 190 } 191 192 //6 193 void DelteAndFree_list(LinkList root) 194 { 195 LinkList s,p,t,k; 196 int min,max; 197 if(root==NULL) 198 printf("单链表无数据,请先新建单链表。 "); 199 else 200 { 201 202 printf("请输入所要min的值,max的值(min < max): "); 203 scanf("%d%d",&min,&max); 204 s=root->next; 205 p=root; 206 while(s->data<min) 207 { 208 s=s->next; 209 p=p->next; 210 } 211 t=p; 212 while(s->data<max) 213 { 214 s=s->next; 215 t=t->next; 216 } 217 s=p->next; 218 p->next=t->next->next; 219 t->next=NULL; 220 while(s->next!=NULL) 221 { 222 k=s; 223 s=s->next; 224 free(k); 225 } 226 free(s); 227 } 228 return; 229 230 } 231 232 //删除公共元素 233 void DeleteCommon_list(LinkList root) 234 { 235 LinkList s,p,t; 236 if(root->next->next==NULL) 237 printf("单链表无数据,请先新建单链表。 "); 238 else 239 { 240 s=root->next; 241 p=root->next->next; 242 while(p->next!=NULL) 243 { 244 if(s->data==p->data) 245 { 246 t=p; 247 p=p->next; 248 s->next=p; 249 free(t); 250 } 251 else 252 { 253 s=s->next; 254 p=p->next; 255 } 256 } 257 } 258 return; 259 } 260 261 262 //链表的逆置 263 void Reserve_list(LinkList root) 264 { 265 LinkList s,p,t; 266 s=root->next; 267 root->next=NULL; 268 while(s->next!=NULL) 269 { 270 p=s->next; 271 s->next=root->next; 272 root->next=s; 273 s=p; 274 } 275 LinkList head; 276 head=(LinkList)malloc(m); 277 head->next=NULL; 278 t=root; 279 while(t->next!=NULL) 280 { 281 t=t->next; 282 } 283 t->next=head; 284 return; 285 } 286 287 //打印菜单 288 void print() 289 { 290 printf(" 菜单如下: "); 291 printf("1.建立单链表 "); 292 printf("2.计算单链表的长度并输出 "); 293 printf("3.查找值为x的直接前驱结点q "); 294 printf("4.删除值为x的节点 "); 295 printf("5.逆置单链表 "); 296 printf("6.将单链表递增排序后删除表中所有值大于mink且小于maxk的元素 "); 297 printf("7.将单链表递增排序后删除表中所有值相同的多余元素 "); 298 printf("8.分解单链表,一个为奇数,另一个为偶数 "); 299 printf("0.EXIT "); 300 printf("请输入你选菜单的数字: "); 301 } 302 303 //循环菜单 304 int main(void) 305 { 306 LinkList root; 307 int x; 308 root = (LinkList)malloc(m); 309 root->next = NULL; 310 root->next = (LinkList)malloc(m); 311 root->next->next = NULL; 312 bool flag; 313 int op; 314 print(); 315 316 //show_arr(&arr); 317 318 while(scanf("%d",&op)!=EOF) 319 { 320 flag=true; 321 switch(op) 322 { 323 case 0: 324 flag=false; 325 break; 326 case 1: 327 Bulid_List(root); 328 break; 329 case 2: 330 OutPut_list(root); 331 break; 332 case 3: 333 printf("请输入所要查找的x: "); 334 scanf("%d",&x); 335 Find_list(root,x); 336 break; 337 case 4: 338 printf("请输入所要删除值x: "); 339 scanf("%d",&x); 340 Delete_list(root,x); 341 break; 342 case 5: 343 Reserve_list(root); 344 break; 345 case 6: 346 DelteAndFree_list(root); 347 break; 348 case 7: 349 DeleteCommon_list(root); 350 break; 351 case 8: 352 Divid(root); 353 break; 354 default: 355 printf("您真笨,输入的数字非法,程序已退出!! "); 356 break; 357 } 358 359 if(!flag) 360 { 361 printf("程序将退出!!谢谢使用!! "); 362 break; 363 } 364 else{ 365 print(); 366 } 367 } 368 369 return 0; 370 }
三、栈和队列的基本操作
1 实验四:栈和队列的基本操作 2 3 (1)采用链式存储实现栈的初始化、入栈、出栈操作。 4 (2)采用顺序存储实现栈的初始化、入栈、出栈操作。 5 (3)采用链式存储实现队列的初始化、入队、出队操作。 6 (4)采用顺序存储实现循环队列的初始化、入队、出队操作。 7 (5)在主函数中设计一个简单的菜单,分别测试上述算法。 8 9 综合训练:(1)利用栈实现表达式求值算法。 10 (2)利用栈实现迷宫求解。 11 (3)编写c语言程序利用队列打印一个杨辉三角形的前n行。 12 1 13 1 1 14 1 2 1 15 1 3 3 1 16 1 4 6 4 1 17 18 #include<stdio.h> 19 #include"xxb.h" 20 21 int main() 22 { 23 24 print(); 25 int ncase, n1, n2, n3, n4; 26 bool flag = true; 27 bool f1, f2, f3, f4; 28 SqStack s; 29 LinkLStack ls; 30 SqQueue Q; 31 LinkQueue LQ; 32 int e; 33 while(scanf("%d",&ncase) != EOF) 34 { 35 f1 = true; 36 f2 = true; 37 f3 = true; 38 f4 = true; 39 switch(ncase) 40 { 41 case 1: 42 print1(); 43 IniLStack(ls); 44 while(scanf("%d",&n1) != EOF) 45 { 46 47 switch(n1) 48 { 49 case 1: 50 if(IniLStack(ls)) 51 printf("链式栈建立成功! "); 52 else 53 printf("链式栈建立失败! "); 54 break; 55 case 2: 56 if(PushLStack(ls, e)) 57 printf("入栈成功! "); 58 else 59 printf("入栈失败! "); 60 break; 61 case 3: 62 if(PopLStack(ls, e)) 63 printf("e = %d出栈成功! ", e); 64 else 65 printf("栈为空! "); 66 break; 67 68 case 0: 69 f1 = false; 70 break; 71 default: 72 printf(" 输入有误,请重新输入! "); 73 break; 74 } 75 if(!f1) 76 break; 77 print1(); 78 } 79 break; 80 case 2: 81 print2(); 82 while(scanf("%d",&n2) != EOF) 83 { 84 switch(n2) 85 { 86 case 1: 87 if(Initack(s)) 88 printf("顺序栈建立成功! "); 89 else 90 printf("顺序建立失败! "); 91 break; 92 case 2: 93 if(Push(s,e)) 94 printf("入栈成功! "); 95 else 96 printf("入栈失败! "); 97 break; 98 case 3: 99 if(!Pop(s, e)) 100 printf("顺序栈为空! "); 101 else 102 printf("e = %d出栈成功! ", e); 103 break; 104 case 0: 105 f2 = false; 106 break; 107 default: 108 printf(" 输入有误,请重新输入! "); 109 break; 110 } 111 if(!f2) 112 break; 113 print2(); 114 } 115 break; 116 case 3: 117 print3(); 118 while(scanf("%d",&n3) != EOF) 119 { 120 switch(n3) 121 { 122 case 1: 123 if(InitQueue(LQ)) 124 printf("链式队列构造成功! "); 125 else 126 printf("链式队列构造失败! "); 127 break; 128 case 2: 129 printf("请输入如队列元素e="); 130 scanf("%d",&e); 131 if(EnQueue(LQ, e)) 132 printf("链式队列入列成功! "); 133 else 134 printf("链式队列入列失败! "); 135 break; 136 case 3: 137 if(DeQueue(LQ, e)) 138 printf("e = %d出队列成功! ", e); 139 else 140 printf("队列为空! "); 141 break; 142 case 0: 143 f4 = false; 144 break; 145 default: 146 printf(" 输入有误,请重新输入! "); 147 break; 148 } 149 if(!f4) 150 break; 151 print4(); 152 } 153 break; 154 case 4: 155 print4(); 156 while(scanf("%d",&n4) != EOF) 157 { 158 switch(n4) 159 { 160 case 1: 161 if(InitQueue(Q)) 162 printf("顺序队列初始化成功! "); 163 else 164 printf("顺序队列初始化失败! "); 165 break; 166 case 2: 167 printf("请输入如队列元素e="); 168 scanf("%d",&e); 169 if(EnQueue(Q, e)) 170 printf("插入队列成功! "); 171 else 172 printf("插入失败! "); 173 break; 174 case 3: 175 if(DeQueue(Q, e)) 176 printf("e = %d出队列成功! ", e); 177 else 178 printf("队列为空! "); 179 break; 180 case 0: 181 f3 = false; 182 break; 183 default: 184 printf(" 输入有误,请重新输入! "); 185 break; 186 } 187 if(!f3) 188 break; 189 print3(); 190 } 191 break; 192 case 0: 193 flag = false; 194 195 break; 196 default: 197 printf(" 输入错误,请重新输入,谢谢! "); 198 break; 199 } 200 if(!flag) 201 break; 202 print(); 203 } 204 205 return 0; 206 }
四、二叉树的基本操作
1 实验五:二叉树的基本操作 2 3 (1)输入字符序列,建立二叉链表。 4 (2)先序、中序、后序遍历二叉树:递归算法。 5 (3)中序遍历二叉树:非递归算法。(最好也能实现先序、后序非递归算法) 6 (4)求二叉树的高度 。 7 (5)求二叉树的叶子个数。 8 (6)借助队列实现二叉树的层次遍历。 9 (7)在主函数中设计一个简单的菜单,分别调试上述算法。 10 11 #include<stdio.h> 12 #include<stdlib.h> 13 14 #define OK 1 15 #define ERROR 0 16 #define OVERFLOW -1 17 #define LIST_INT_SIZE 100 18 #define LISTINCREMENT 10 19 20 int dep, count= 0; 21 22 typedef int Status; 23 typedef char TElemType; 24 25 typedef struct BiTNode{ 26 TElemType data; 27 struct BiTNode *lchild, *rchild; 28 }BiTNode, *BiTree; 29 30 //建立二叉树 31 Status CreateBiTree(BiTree &T) 32 { 33 char ch; 34 35 getchar(); 36 scanf("%c", &ch); 37 if(ch == ' '|| ch == ' ') 38 { 39 T = NULL; 40 return ERROR; 41 } 42 else 43 { 44 T = (BiTree)malloc(sizeof(BiTNode)); 45 T->data = ch; 46 printf("请输入%c的左孩子:", T->data); 47 CreateBiTree(T->lchild); 48 printf("请输入%c的右孩子:", T->data); 49 CreateBiTree(T->rchild); 50 return OK; 51 } 52 } 53 54 55 56 //主菜单 57 void print() 58 { 59 printf(" 菜单如下: "); 60 printf("1 . 输入字符序列,建立二叉链表 "); 61 printf("2 . 先序、中序、后序遍历二叉树:递归算法 "); 62 printf("3 . 先序、中序、后序遍历二叉树:非递归算法 "); 63 printf("4 . 求二叉树的高度 "); 64 printf("5 . 求二叉树的叶子个数 "); 65 printf("6 . 借助队列实现二叉树的层次遍历 "); 66 printf("0 . EXIT 请选择操作序号:"); 67 } 68 69 //先序、中序、后序遍历二叉树:递归算法 70 void print2() 71 { 72 printf(" 递归算法遍历二叉树,菜单如下: "); 73 printf("1.先根遍历 "); 74 printf("2.中序遍历 "); 75 printf("3.后续遍历 "); 76 printf("0.退出 "); 77 printf("请输入二级菜单选择:"); 78 } 79 80 Status Visit(BiTree T) 81 { 82 if(T) 83 { 84 printf("%c ", T->data); 85 return OK; 86 } 87 } 88 89 Status PrintElement(TElemType e) 90 { 91 printf(" %c ", e); 92 return OK; 93 } 94 95 //先序 96 Status PreOrderTraverse(BiTree T, Status (*Visit)(TElemType e)) 97 { 98 if(T) 99 { 100 if(Visit(T->data)) 101 if(PreOrderTraverse(T->lchild, Visit)) 102 if(PreOrderTraverse(T->rchild, Visit)) 103 return OK; 104 return ERROR; 105 } 106 else 107 return OK; 108 } 109 110 //中序 111 Status MidOrderTraverse(BiTree T, Status (*Visit)(TElemType e)) 112 { 113 if(T) 114 { 115 if(MidOrderTraverse(T->lchild, Visit)) 116 if(Visit(T->data)) 117 if(MidOrderTraverse(T->rchild, Visit)) 118 return OK; 119 return ERROR; 120 } 121 else 122 return OK; 123 } 124 //后序 125 Status LastOrderTraverse(BiTree T, Status (*Visit)(TElemType e)) 126 { 127 if(T) 128 { 129 if(LastOrderTraverse(T->lchild, Visit)) 130 if(LastOrderTraverse(T->rchild, Visit)) 131 if(Visit(T->data)) 132 return OK; 133 return ERROR; 134 } 135 else 136 return OK; 137 } 138 139 //求树的叶子的个数,和打印出叶子 140 Status LeafNumTree(BiTree T) 141 { 142 int lnum,rnum; 143 if(T!=NULL) 144 { 145 if(T->lchild==NULL && T->rchild==NULL) 146 return 1; 147 else 148 { 149 lnum=LeafNumTree(T->lchild); 150 rnum=LeafNumTree(T->rchild); 151 return lnum+rnum; 152 } 153 } 154 return 0; 155 } 156 157 //求二叉树的高度 158 Status BiTreeDepth(BiTree T) 159 { 160 int l,r; 161 if(T) 162 { 163 l=BiTreeDepth(T->lchild); 164 r=BiTreeDepth(T->rchild); 165 if(l>=r) 166 dep += l; 167 else dep += r; 168 } 169 else 170 return 1; 171 } 172 173 //先序、中序、后序遍历二叉树:非递归算法 174 void print3() 175 { 176 printf(" 非递归算法遍历二叉树,菜单如下: "); 177 printf("1.先根遍历 "); 178 printf("0.退出 "); 179 printf("请输入二级菜单选择:"); 180 } 181 182 typedef struct QueueNode 183 { 184 BiTree e; 185 struct QueueNode *next; 186 }QueueNode,*QueuePtr; //定义队列结点结构 187 typedef struct 188 { 189 QueuePtr front; 190 QueuePtr rear; 191 }LinkQueue; 192 193 194 //栈的顺序存储表示 195 typedef struct 196 { BiTNode *base; //栈底指针 197 BiTNode *top; //栈顶指针 198 int stacksize; //当前已分配的存储空间 199 }SqStack; 200 201 //初始化一个带头结点的队列 202 void InitQueue(LinkQueue &q) 203 { 204 q.front=q.rear=(QueuePtr)malloc(sizeof(QueueNode)); 205 q.front->next=NULL; 206 } 207 208 //入队列 209 void enqueue(LinkQueue &q,BiTree p) 210 { 211 QueuePtr s; 212 int first=1; 213 s=(QueuePtr)malloc(sizeof(QueueNode)); 214 s->e =p; 215 s->next=NULL; 216 q.rear->next=s; 217 q.rear=s; 218 } 219 220 //出队列 221 void dequeue(LinkQueue &q,BiTree &p) 222 { 223 char data; 224 QueuePtr s; 225 s=q.front->next; 226 p=s->e ; 227 data=p->data; 228 q.front->next=s->next; 229 if(q.rear==s) 230 q.rear=q.front; 231 free(s); 232 printf("%c ",data); 233 } 234 235 //判断队列是否为空 236 Status queueempty(LinkQueue q) 237 { 238 if(q.front->next==NULL) 239 return 1; 240 return 0; 241 } 242 //按层次遍历树中结点 243 void Traverse(BiTree T) 244 { 245 LinkQueue q; 246 BiTree p; 247 InitQueue(q); 248 p=T; 249 enqueue(q,p); 250 while(queueempty(q)!=1) 251 { 252 dequeue(q,p); 253 if(p->lchild!=NULL) 254 enqueue(q,p->lchild); 255 if(p->rchild!=NULL) 256 enqueue(q,p->rchild); 257 } 258 printf(" "); 259 } 260 261 //建立一个空栈 262 void InitStack(SqStack &S) 263 { S.base=(BiTree)malloc(LIST_INT_SIZE * sizeof(BiTNode)); 264 if(!S.base) 265 exit(OVERFLOW );//存储分配失败 266 S.top=S.base; 267 S.stacksize=LIST_INT_SIZE; 268 } 269 270 //压入栈 271 void Push(SqStack & S,BiTree p) 272 { if(S.top-S.base>=S.stacksize)//满栈,追加存储结构 273 { S.base= (BiTree)realloc(S.base,(S.stacksize+LISTINCREMENT) * sizeof(BiTNode)); 274 if(!S.base) exit(OVERFLOW );//存储分配失败 275 S.top=S.base+S.stacksize; 276 S.stacksize+=LISTINCREMENT; 277 } 278 *(++S.top)=*p; 279 } 280 281 //退出栈 282 bool Pop(SqStack &S,BiTree &p) 283 { if( S.top==S.base) 284 { printf("空栈 "); 285 return false; 286 } 287 p=(BiTree)malloc( sizeof(BiTNode)); 288 *p=*S.top; 289 --S.top; 290 return true; 291 } 292 293 //判断是否是空栈 294 bool StackEmpty(SqStack &S) 295 { if( S.top==S.base) 296 return true; 297 else 298 return false ; 299 } 300 301 302 Status InOrderTraverAndCountLeaf(BiTree &T,Status(* Vist)(TElemType e)) 303 { int j=0,count=0; 304 BiTree p; 305 p=(BiTNode *)malloc( sizeof(BiTNode));//关键一步 306 p=T; 307 SqStack s; 308 InitStack(s); 309 while(p||!StackEmpty(s)) 310 { if(p) 311 { Push(s,p);//如果p为非空,将p压入栈 312 if(!(p->lchild)&&!(p->rchild)) 313 ++count;//记录叶子节点数 314 p=p->lchild; 315 }//if 316 else 317 { 318 Pop(s,p);//如果p为空,则p退栈 319 Vist(p->data); 320 p=p->rchild; 321 }//else 322 }//while 323 return count; 324 } 325 326 int main() 327 { 328 int n, ncase; 329 int count; 330 bool f, f1, f2, f3; 331 BiTree T; 332 TElemType e; 333 print(); 334 while(scanf("%d", &n)!=EOF) 335 { 336 337 f = true; 338 339 switch(n) 340 { 341 case 1: 342 printf("输入空格或回车表示此结点为空结束 请输入头结点:"); 343 if(CreateBiTree(T)) 344 printf("二叉树建立成功! "); 345 else 346 printf("二叉树建立失败! "); 347 break; 348 case 2: 349 print2(); 350 while(scanf("%d", &ncase)!= EOF) 351 { 352 f1 = true; 353 switch(ncase) 354 { 355 case 1: 356 printf("先序遍历顺序为:"); 357 if(PreOrderTraverse(T, PrintElement)) 358 printf("先序遍历成功! "); 359 else 360 printf("先序遍历失败! "); 361 break; 362 case 2: 363 printf("中序遍历顺序为:"); 364 if(MidOrderTraverse(T, PrintElement)) 365 printf("中序遍历成功! "); 366 else 367 printf("中序遍历失败! "); 368 break; 369 case 3: 370 printf("后序遍历顺序为:"); 371 if(LastOrderTraverse(T, PrintElement)) 372 printf("后序遍历成功! "); 373 else 374 printf("后序遍历失败! "); 375 break; 376 case 0: 377 f1 = false; 378 break; 379 default : 380 printf("输入错误,请重新输入! "); 381 } 382 if(!f1) 383 break; 384 print2(); 385 } 386 387 break; 388 case 3: 389 print3(); 390 while(scanf("%d", &ncase)!= EOF) 391 { 392 f2 = true; 393 switch(ncase) 394 { 395 case 1: 396 InOrderTraverAndCountLeaf(T,PrintElement); 397 break; 398 case 0: 399 f2 = false; 400 break; 401 default : 402 printf("输入错误,请重新输入! "); 403 } 404 if(!f2) 405 break; 406 print3(); 407 } 408 409 break; 410 case 4: 411 dep = 0; 412 BiTreeDepth(T); 413 printf("二叉树的高度为:%d ", dep-1); 414 break; 415 case 5: 416 count = LeafNumTree(T); 417 printf("二叉树的叶子个数为:%d ", count); 418 break; 419 case 6: 420 printf("按层次遍历的顺序为: "); 421 Traverse(T); 422 printf(" "); 423 break; 424 case 0: 425 f = false; 426 break; 427 default: 428 printf("输入错误,请重新输入! "); 429 break; 430 } 431 if(!f) 432 { 433 printf("退出程序... "); 434 break; 435 } 436 print(); 437 } 438 439 return 0; 440 }
五、哈夫曼编码
1 实验六:哈夫曼编码 2 3 已知某系统在通信联络中只可能出现8种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计哈夫曼编码。 4 5 综合训练:试编写一个将百分制分数转换为五级分制的程序。要求其时间性能尽可能好(即平均比较次数尽可能少)。假设学生成绩的分布情况如下: 6 分数 0-59 60-69 70-79 80-89 90-100 7 比例 0.05 0.15 0.40 0.30 0.10 8 9 #include<stdio.h> 10 #include<stdlib.h> 11 #include<string.h> 12 #define ERROR 0 13 #define OK 1 14 typedef int Status; 15 typedef struct {//声明赫夫曼树的结点 16 int weight; 17 int parent; 18 int lchild; 19 int rchild; 20 }Htnode,*Huffmantree; 21 typedef char ** Huffmancode;//相当于声明一个二维数组,来记录每个权值对应的编码。 22 void Select (Huffmantree &HT,int t,int &p,int &q);//选择结点中权值最小的两个结点,用p,q来返回。 23 void creathuffmantree(Huffmantree &HT,Huffmancode &HC,int *w,int n)//创建赫夫曼树。 24 { 25 int m,i,p,q,j,start,s; 26 if(n<=1) 27 return; 28 m=2*n-1;//当n大于1时,就需要2*n-1个结点 29 HT=(Huffmantree)malloc(sizeof(Htnode)*(m+1));//因为0不存东西,而从1开始存,所以申请m+1个空间。 30 for(i=1;i<=n;i++)//对叶子结点进行初始化,除权之外全赋值为0。 31 { 32 HT[i].weight=w[i-1]; 33 HT[i].parent=0; 34 HT[i].rchild=0; 35 HT[i].lchild=0; 36 } 37 for(i=n+1;i<=m;i++)//对非叶子结点进行初始化,所有的值全为0 38 { 39 HT[i].weight=0; 40 HT[i].parent=0; 41 HT[i].rchild=0; 42 HT[i].lchild=0; 43 } 44 for(i=n+1;i<=m;i++)//这是创建树的主要步骤,找出权值和最小的两棵树,再把它们合并成一棵树,依次进行,知道走后还剩仅有的一棵树。 45 { 46 Select(HT,i-1,p,q);//这是选择权值最小的两棵树的函数,并用p,q来返回,在上面已经声明过。 47 HT[i].weight=HT[p].weight+HT[q].weight;//对刚合并的新树的根结点的权值进行赋值。 48 HT[i].lchild=p;//新树的左孩子赋为p; 49 HT[i].rchild=q;//新树的右孩子赋为q; 50 HT[p].parent=i;//把他们的双亲都赋为i; 51 HT[q].parent=i; 52 } 53 HC=(Huffmancode)malloc(sizeof(char*)*(n+1));//申请一个大小为n+1的存放指针的数组。 54 char* cd=(char*)malloc(sizeof(char)*n);//申请一个一维数组,作为一个中转站,最后把他复制到HC中的一个数组中。 55 56 for(i=1;i<=n;i++)//对赫夫曼树的数组从1到n进行依次遍历,这是从叶子结点到根节点。 57 { 58 start=n-1;//对这个一位数组进行倒着存,最后正着读取。 59 cd[start]='