数据结构
一、顺序表的基本操作
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个数据元素。\n"); 203 printf("1.输出顺序表L1及其长度\n"); 204 printf("2.删除给定位置i的结点\n"); 205 printf("3.在顺序表中删除值为x的结点\n"); 206 printf("4.逆置顺序表\n"); 207 printf("5.将顺序表按升序排序\n"); 208 printf("6.设顺序表中的数据元素递增有序,将x插入到顺序表的适当位置上,以保持该表的有序性\n"); 209 printf("7.将两个顺序有序表L和L1合并为一个有序表L2\n"); 210 printf("0.退出操作系统。\n"); 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("\n"); 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\n",L.length); 269 break; 270 case 2: 271 printf("请输入要删除的节点:"); 272 scanf("%d",&i);//删除顺序表的节点 273 if(ListDelete(L,i)) 274 { 275 printf("删除成功!\n"); 276 printSqList(L); 277 } 278 else 279 printf("删除失败!\n"); 280 break; 281 case 3: 282 printf("请输入要删除的节点x的值:"); 283 scanf("%d",&x); 284 if(DeleteX(L,x)) 285 { 286 printf("删除成功!\n顺序表为:"); 287 printSqList(L); 288 } 289 else 290 printf("删除失败!\n"); 291 break; 292 case 4: 293 //逆序顺序表 294 if(TurnArrond(L)) 295 { 296 printf("逆序成功!\n"); 297 printf("顺序表的次序为:"); 298 printSqList(L); 299 } 300 else 301 printf("逆序失败!\n"); 302 break; 303 case 5: 304 //顺序表升序排列 305 if(ABC(L)) 306 { 307 printf("顺序表升序排列成功!\n"); 308 printf("顺序表的次序为:"); 309 printSqList(L); 310 } 311 else 312 printf("顺序表升序排列失败!\n"); 313 314 printf("请输入要插入的数据:"); 315 scanf("%d",&e); 316 if(ListInsertABC(L,e)) 317 { 318 printf("顺序插入成功!\n"); 319 printf("顺序表的次序为:"); 320 printSqList(L); 321 } 322 323 else 324 printf("顺序插入失败!\n"); 325 break; 326 case 6: 327 ABC(L); 328 printf("请输入要插入的数字x的值:"); 329 scanf("%d",&x); 330 if(ListInsertABC(L,x)) 331 { 332 printf("操作成功!\n"); 333 printf("顺序表的次序为:"); 334 printSqList(L); 335 } 336 else printf("操作失败!\n"); 337 break; 338 case 7: 339 if(MergeList(L,L1,L2)) 340 { 341 printf("顺序表L,L1合并成功!\n"); 342 //printf("顺序表的次序为:"); 343 //printSqList(L2); 344 } 345 else 346 printf("顺序表合并失败!\n"); 347 break; 348 default: 349 break; 350 } 351 if(!flag) 352 break; 353 printf("\n请输入你要的下一步操作序号:"); 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数据:\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("链表已建立!\n"); 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("单链表无数据,请先新建单链表。\n"); 55 else 56 { 57 while(s->next!=NULL) 58 { 59 s=s->next; 60 len++; 61 } 62 printf("单链表的长度为:%d\n",len); 63 printf("单链表的数据如下:\n"); 64 s=root->next; 65 while(s->next!=NULL) 66 { 67 printf("%d ",s->data); 68 s=s->next; 69 } 70 printf("\n"); 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("单链表无数据,请先新建单链表。\n"); 80 else 81 { 82 s=root->next; 83 p=root->next->next; 84 if(s->data==x) 85 printf("此X值无前驱结点。\n"); 86 else 87 { 88 while(p->next!=NULL) 89 { 90 if(p->data==x) 91 { 92 printf("此X值的前驱结点的值为:%d\n",s->data); 93 return; 94 } 95 else 96 { 97 s=p; 98 p=p->next; 99 } 100 } 101 printf("此链表不存在值为X的结点。\n"); 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("单链表无数据,请先新建单链表。\n"); 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("待删除的数据不存在。\n"); 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("构建成功!\n"); 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("\n偶数链表为:"); 183 p=head_odd; 184 while(p->next!=NULL) 185 { 186 printf("%d ",p->next->data); 187 p=p->next; 188 } 189 printf("\n"); 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("单链表无数据,请先新建单链表。\n"); 199 else 200 { 201 202 printf("请输入所要min的值,max的值(min < max):\n"); 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("单链表无数据,请先新建单链表。\n"); 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("\n菜单如下:\n"); 291 printf("1.建立单链表\n"); 292 printf("2.计算单链表的长度并输出\n"); 293 printf("3.查找值为x的直接前驱结点q\n"); 294 printf("4.删除值为x的节点\n"); 295 printf("5.逆置单链表\n"); 296 printf("6.将单链表递增排序后删除表中所有值大于mink且小于maxk的元素\n"); 297 printf("7.将单链表递增排序后删除表中所有值相同的多余元素\n"); 298 printf("8.分解单链表,一个为奇数,另一个为偶数\n"); 299 printf("0.EXIT\n\n"); 300 printf("请输入你选菜单的数字:\n"); 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:\n"); 334 scanf("%d",&x); 335 Find_list(root,x); 336 break; 337 case 4: 338 printf("请输入所要删除值x:\n"); 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("您真笨,输入的数字非法,程序已退出!!\n"); 356 break; 357 } 358 359 if(!flag) 360 { 361 printf("程序将退出!!谢谢使用!!\n"); 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("链式栈建立成功!\n"); 52 else 53 printf("链式栈建立失败!\n"); 54 break; 55 case 2: 56 if(PushLStack(ls, e)) 57 printf("入栈成功!\n"); 58 else 59 printf("入栈失败!\n"); 60 break; 61 case 3: 62 if(PopLStack(ls, e)) 63 printf("e = %d出栈成功!\n", e); 64 else 65 printf("栈为空!\n"); 66 break; 67 68 case 0: 69 f1 = false; 70 break; 71 default: 72 printf(" 输入有误,请重新输入!\n"); 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("顺序栈建立成功!\n"); 89 else 90 printf("顺序建立失败!\n"); 91 break; 92 case 2: 93 if(Push(s,e)) 94 printf("入栈成功!\n"); 95 else 96 printf("入栈失败!\n"); 97 break; 98 case 3: 99 if(!Pop(s, e)) 100 printf("顺序栈为空!\n"); 101 else 102 printf("e = %d出栈成功!\n", e); 103 break; 104 case 0: 105 f2 = false; 106 break; 107 default: 108 printf(" 输入有误,请重新输入!\n"); 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("链式队列构造成功!\n"); 125 else 126 printf("链式队列构造失败!\n"); 127 break; 128 case 2: 129 printf("请输入如队列元素e="); 130 scanf("%d",&e); 131 if(EnQueue(LQ, e)) 132 printf("链式队列入列成功!\n"); 133 else 134 printf("链式队列入列失败!\n"); 135 break; 136 case 3: 137 if(DeQueue(LQ, e)) 138 printf("e = %d出队列成功!\n", e); 139 else 140 printf("队列为空!\n"); 141 break; 142 case 0: 143 f4 = false; 144 break; 145 default: 146 printf(" 输入有误,请重新输入!\n"); 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("顺序队列初始化成功!\n"); 163 else 164 printf("顺序队列初始化失败!\n"); 165 break; 166 case 2: 167 printf("请输入如队列元素e="); 168 scanf("%d",&e); 169 if(EnQueue(Q, e)) 170 printf("插入队列成功!\n"); 171 else 172 printf("插入失败!\n"); 173 break; 174 case 3: 175 if(DeQueue(Q, e)) 176 printf("e = %d出队列成功!\n", e); 177 else 178 printf("队列为空!\n"); 179 break; 180 case 0: 181 f3 = false; 182 break; 183 default: 184 printf(" 输入有误,请重新输入!\n"); 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(" 输入错误,请重新输入,谢谢!\n"); 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 == '\n') 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("\n菜单如下:\n"); 60 printf("1 . 输入字符序列,建立二叉链表\n"); 61 printf("2 . 先序、中序、后序遍历二叉树:递归算法\n"); 62 printf("3 . 先序、中序、后序遍历二叉树:非递归算法\n"); 63 printf("4 . 求二叉树的高度 \n"); 64 printf("5 . 求二叉树的叶子个数\n"); 65 printf("6 . 借助队列实现二叉树的层次遍历\n"); 66 printf("0 . EXIT\n请选择操作序号:"); 67 } 68 69 //先序、中序、后序遍历二叉树:递归算法 70 void print2() 71 { 72 printf("\n递归算法遍历二叉树,菜单如下:\n"); 73 printf("1.先根遍历\n"); 74 printf("2.中序遍历\n"); 75 printf("3.后续遍历\n"); 76 printf("0.退出\n"); 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("\n非递归算法遍历二叉树,菜单如下:\n"); 177 printf("1.先根遍历\n"); 178 printf("0.退出\n"); 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\t",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("\n"); 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("空栈\n"); 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("输入空格或回车表示此结点为空结束\n请输入头结点:"); 343 if(CreateBiTree(T)) 344 printf("二叉树建立成功!\n"); 345 else 346 printf("二叉树建立失败!\n"); 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("先序遍历成功!\n"); 359 else 360 printf("先序遍历失败!\n"); 361 break; 362 case 2: 363 printf("中序遍历顺序为:"); 364 if(MidOrderTraverse(T, PrintElement)) 365 printf("中序遍历成功!\n"); 366 else 367 printf("中序遍历失败!\n"); 368 break; 369 case 3: 370 printf("后序遍历顺序为:"); 371 if(LastOrderTraverse(T, PrintElement)) 372 printf("后序遍历成功!\n"); 373 else 374 printf("后序遍历失败!\n"); 375 break; 376 case 0: 377 f1 = false; 378 break; 379 default : 380 printf("输入错误,请重新输入!\n"); 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("输入错误,请重新输入!\n"); 403 } 404 if(!f2) 405 break; 406 print3(); 407 } 408 409 break; 410 case 4: 411 dep = 0; 412 BiTreeDepth(T); 413 printf("二叉树的高度为:%d\n", dep-1); 414 break; 415 case 5: 416 count = LeafNumTree(T); 417 printf("二叉树的叶子个数为:%d\n", count); 418 break; 419 case 6: 420 printf("按层次遍历的顺序为:\n"); 421 Traverse(T); 422 printf("\n"); 423 break; 424 case 0: 425 f = false; 426 break; 427 default: 428 printf("输入错误,请重新输入!\n"); 429 break; 430 } 431 if(!f) 432 { 433 printf("退出程序...\n"); 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]='\0'; 60 s=i; 61 while(HT[s].parent!=0) 62 { 63 j=s; 64 s=HT[s].parent; 65 if(HT[s].lchild==j)//如果该结点是双亲结点的左孩子,应该把它赋为0; 66 cd[--start]='0'; 67 if(HT[s].rchild==j)//如果该结点是双亲结点的右孩子,应该把它赋为1; 68 cd[--start]='1'; 69 } 70 HC[i]=(char *)malloc(sizeof(char)*(n-start)); 71 strcpy(HC[i],&cd[start]);//把cd数组里的内容复制到HC[i]里,再用cd去盛其他的编码。 72 } 73 free(cd);//最后可以把cd数组给释放了。 74 } 75 void Select (Huffmantree & HT,int t,int &min1,int &min2)//选择结点中权值最小的两个结点,用p,q来返回。 76 { 77 int i=1,flag=0; 78 while(flag<2)//这个while循环是为了找出前两棵树的根结点,把他们当成最小的两棵树,以后来做比较,求出最小的两个。 79 { 80 if(HT[i].parent!=0)//如果不是根结点,继续朝后找,直到找到根结点。 81 i++; 82 else//如果是根结点,就把他们分别赋给min1和min2. 83 { 84 if(flag==0) 85 min1=i; 86 else 87 min2=i; 88 flag++; 89 i++; 90 } 91 } 92 if(HT[min1].weight>HT[min2].weight)//对min1和min2进行比较,把最小的的付给min1,第二小的付给min2. 93 { 94 t=min1; 95 min1=min2; 96 min2=t; 97 } 98 while(i<=t)//把以后的各个结点的权值与最小的两个比较,调整下,最后得出的就是最小的两个结点。 99 { 100 if(HT[i].parent!=0)//如果不是根结点,继续朝后找,直到找到根结点。 101 i++; 102 else 103 { 104 if(HT[i].weight<=HT[min1].weight)//如果该结点的权值比最小的结点还小,把最小的两个全重新赋值。 105 { 106 min2=min1; 107 min1=i; 108 } 109 else if(HT[i].weight>=HT[min1].weight&&HT[i].weight<=HT[min2].weight)//如果该结点的权值在最小和第二小之间的话, 110 //就把第二小的重新赋值。 111 min2=i; 112 i++; 113 } 114 } 115 116 } 117 Status exhuffmantree(Huffmantree &HT,int m,char *code,int *ex,int &j)//这是解码的函数,m为那棵树的根结点,code是输入的赫夫曼码, 118 //解码后最后给他存到ex数组中,j为数组的长度。 119 { 120 int i=0,k=m; 121 while(code[i]!='\0')//从根结点到叶子节点去匹配,输出最后的那个权值 122 { 123 if(code[i]=='0'&&HT[k].lchild!=0)//如果code[i]是0,并且左孩子不为0,则继续朝叶子结点找。 124 { 125 k=HT[k].lchild; 126 i++; 127 } 128 else if(code[i]=='1'&&HT[k].rchild!=0)//如果code[i]是1,并且右孩子不为0,则继续朝叶子结点找。 129 { 130 k=HT[k].rchild; 131 i++; 132 } 133 else if(HT[k].rchild==0&&HT[k].lchild==0)//如果是叶子结点,则把它的权值赋给ex[j]. 134 { 135 ex[j]=HT[k].weight; 136 j++; 137 k=m; 138 } 139 else//其他的则返回ERROR。 140 return ERROR; 141 } 142 if(HT[k].rchild==0&&HT[k].lchild==0)//当跳出循环的时候,说明应该到了叶子结点,如果是叶子结点,则把它的权值赋给ex[j]. 143 { 144 ex[j]=HT[k].weight; 145 return OK; 146 } 147 else//其他的则返回ERROR。 148 return ERROR; 149 } 150 int main() 151 { 152 Huffmantree HT; 153 Huffmancode HC; 154 char Code[100]; 155 int i, n,a[100],b[100],j=0,t; 156 printf("输入叶子结点的个数n为:\n"); 157 scanf("%d",&n); 158 printf("依次输入n个叶子结点的权值为:\n"); 159 for(i=0;i<n;i++) 160 scanf("%d",&a[i]); 161 creathuffmantree(HT,HC,a,n); 162 printf("输出该赫夫曼树各个叶子结点的编码为:\n"); 163 for(i=1;i<=n;i++) 164 { 165 t=0; 166 while(HC[i][t]!='\0') 167 { 168 printf("%c",HC[i][t]); 169 t++; 170 } 171 putchar(' '); 172 } 173 putchar('\n'); 174 getchar(); 175 printf("输入该赫夫曼树关联的要译码的code数组:\n"); 176 gets(Code); 177 exhuffmantree(HT,2*n-1,Code,b,j); 178 printf("输出解码后的各权值为:\n"); 179 for(i=0;i<=j;i++) 180 printf("%d ",b[i]); 181 putchar('\n'); 182 return 0; 183 }
六、图的基本操作
1 实验七:图的基本操作 2 3 (1)键盘输入数据,建立一个有向图的邻接表。 4 (2)输出该邻接表。 5 (3)在有向图的邻接表的基础上计算各顶点的度,并输出。 6 (4)以有向图的邻接表为基础实现输出它的拓扑排序序列。 7 (5)采用邻接表存储实现无向图的深度优先遍历。 8 (6)采用邻接表存储实现无向图的广度优先遍历。 9 (7)采用邻接矩阵存储实现无向图的最小生成树的PRIM算法。 10 (8)采用邻接矩阵存储一个有向图,输出单源点到其它顶点的最短路径。 11 (9)在主函数中设计一个简单的菜单,分别调试上述算法。 12 13 综合训练:为计算机专业设计教学计划:4个学年,每学年2个学期,开设50门课程,每学期所开课程门数尽量均衡,课程的安排必须满足先修关系。 14 #include<stdio.h> 15 #include<stdlib.h> 16 #include<stack> 17 #include<queue> 18 using namespace std; 19 #define max_vertex_num 20 20 #define INFINITY 1000000000 21 typedef struct ArcNode{ 22 int adjvex; 23 struct ArcNode *nextarc; 24 }ArcNode; 25 typedef char vertexType; 26 typedef struct VNode{ 27 vertexType data; 28 ArcNode *firstarc; 29 int count; 30 }VNode,AdjList[max_vertex_num]; 31 typedef struct{ 32 AdjList vertices; 33 int vexnum,arcnum; 34 int degree; 35 36 }ALGraph;//邻接表 37 typedef struct ArcCell{ 38 int adj; 39 }ArcCell,AdjMatrix[max_vertex_num][max_vertex_num]; 40 typedef struct{ 41 char vex[max_vertex_num]; 42 AdjMatrix arc; 43 int vexnum,arcnum; 44 }MGraph;//邻接矩阵 45 ALGraph ALG,InsertALG,UALG; 46 MGraph G; 47 int visit[max_vertex_num]; 48 struct edge{ 49 char adjvex; 50 int lowcost; 51 }closedge[max_vertex_num]; 52 int P[max_vertex_num]; 53 int D[max_vertex_num]; 54 int finial[max_vertex_num]; 55 void print() 56 { 57 printf("(1)键盘输入数据,建立一个有向图的邻接表\n"); 58 printf("(2)输出该邻接表\n"); 59 printf("(3)在有向图的邻接表的基础上计算各顶点的度,并输出\n"); 60 printf("(4)以有向图的邻接表为基础实现输出它的拓扑排序序列\n"); 61 printf("(5)采用邻接表存储实现无向图的深度优先遍历\n"); 62 printf("(6)采用邻接表存储实现无向图的广度优先遍历\n"); 63 printf("(7)采用邻接矩阵存储实现无向图的最小生成树的PRIM算法\n"); 64 printf("(8)采用邻接矩阵存储一个有向图,输出单源点到其它顶点的最短路径\n"); 65 printf("(0)退出程序\n"); 66 } 67 int locatevex(MGraph G,char v) 68 {//查找顶点在图中的位置 69 int i=0; 70 while(i<G.vexnum) 71 { 72 if(v==G.vex[i]) 73 break; 74 else 75 i++; 76 } 77 return i; 78 } 79 void CreateALGraph(ALGraph &ALG,ALGraph &InsertALG) 80 {//创建有向邻接表及其逆邻接表并且其顶点用大写字母表示 81 int i,j,k; 82 ArcNode *s,*r; 83 printf("请输入有向邻接表的顶点数和边数:\n"); 84 scanf("%d%d",&ALG.vexnum,&ALG.arcnum); 85 for(i=0;i<ALG.vexnum;i++) 86 { 87 ALG.vertices[i].data='A'+i; 88 ALG.vertices[i].firstarc=NULL; 89 InsertALG.vertices[i].data='A'+i; 90 InsertALG.vertices[i].firstarc=NULL; 91 } 92 for(k=0;k<ALG.arcnum;k++) 93 { 94 scanf("%d%d",&i,&j); 95 s=(ArcNode*)malloc(sizeof(ArcNode)); 96 r=(ArcNode*)malloc(sizeof(ArcNode)); 97 s->adjvex=j; 98 s->nextarc=ALG.vertices[i].firstarc; 99 ALG.vertices[i].firstarc=s; 100 r->adjvex=i; 101 r->nextarc=InsertALG.vertices[j].firstarc; 102 InsertALG.vertices[j].firstarc=r; 103 } 104 105 106 } 107 void CeratUALGraph(ALGraph &UALG) 108 {//用头插法建立无向邻接表 109 int i,j,k; 110 ArcNode *p; 111 printf("请输入无向邻接表的的顶点数和边数:\n"); 112 scanf("%d%d",&UALG.vexnum,&UALG.arcnum); 113 for(i=0;i<UALG.vexnum;i++) 114 { 115 UALG.vertices[i].data='A'+i; 116 UALG.vertices[i].firstarc=NULL; 117 } 118 for(k=0;k<UALG.arcnum;k++) 119 { 120 scanf("%d%d",&i,&j); 121 p=(ArcNode *)malloc(sizeof(ArcNode)); 122 p->adjvex=j; 123 p->nextarc=UALG.vertices[i].firstarc; 124 UALG.vertices[i].firstarc=p; 125 p=(ArcNode *)malloc(sizeof(ArcNode)); 126 p->adjvex=i; 127 p->nextarc=UALG.vertices[j].firstarc; 128 UALG.vertices[j].firstarc=p; 129 } 130 131 } 132 void CreateUDN(MGraph &G,int a) 133 {//若a==1的时候创建无向邻接矩阵,否则创建有向邻接矩阵 134 int i,j,k,w; 135 char v1,v2; 136 printf("请输入邻接矩阵的顶点数和边数:\n"); 137 scanf("%d%d",&G.vexnum,&G.arcnum); 138 getchar(); 139 for(i=0;i<G.vexnum;i++) 140 scanf("%c",&G.vex[i]); 141 for(i=0;i<G.vexnum;i++) 142 for(j=0;j<G.vexnum;j++) 143 G.arc[i][j].adj=INFINITY; 144 for(k=0;k<G.arcnum;k++) 145 { 146 getchar(); 147 scanf("%c %c %d",&v1,&v2,&w); 148 i=locatevex(G,v1); 149 j=locatevex(G,v2); 150 G.arc[i][j].adj=w; 151 if(a==1) 152 G.arc[j][i].adj=G.arc[i][j].adj; 153 } 154 } 155 void shuchu(ALGraph ALG) 156 {//遍历邻接表并输出 157 int i; 158 ArcNode *p; 159 for(i=0;i<ALG.vexnum;i++) 160 { 161 printf("%d %c ",i,ALG.vertices[i].data); 162 for(p=ALG.vertices[i].firstarc;p!=NULL;p=p->nextarc) 163 printf("%d ",p->adjvex); 164 printf("\n"); 165 } 166 } 167 void Degree(ALGraph ALG,ALGraph InsertALG) 168 {//计算邻接表的度=邻接表的出度+逆邻接表的的出度 169 int i; 170 ArcNode *p; 171 for(i=0;i<ALG.vexnum;i++) 172 { 173 ALG.vertices[i].count=0; 174 for(p=ALG.vertices[i].firstarc;p!=NULL;p=p->nextarc) 175 ALG.vertices[i].count++; 176 } 177 for(i=0;i<ALG.vexnum;i++) 178 { 179 InsertALG.vertices[i].count=0; 180 for(p=InsertALG.vertices[i].firstarc;p!=NULL;p=p->nextarc) 181 InsertALG.vertices[i].count++; 182 } 183 for(i=0;i<ALG.vexnum;i++) 184 { 185 printf("%c的度为:%d\n",'A'+i,ALG.vertices[i].count+InsertALG.vertices[i].count); 186 } 187 188 } 189 void dfs(ALGraph UALG,int v) 190 {//深度优先遍历 191 ArcNode *p; 192 visit[v]=1; 193 printf("%c\n",UALG.vertices[v].data); 194 p=UALG.vertices[v].firstarc; 195 while(p) 196 { 197 if(!visit[p->adjvex]) 198 dfs(UALG,p->adjvex); 199 p=p->nextarc; 200 } 201 202 } 203 void DFSTraverse(ALGraph UALG) 204 { 205 206 for(int i=0;i<UALG.vexnum;i++) 207 visit[i]=0; 208 for(i=0;i<UALG.vexnum;i++) 209 if(!visit[i]) 210 dfs(UALG,i); 211 printf("\n"); 212 } 213 void BFSTraverse(ALGraph UALG) 214 {//广度优先遍历 215 ArcNode *p; 216 int v; 217 queue<int>q; 218 for(int i=0;i<UALG.vexnum;i++) 219 visit[i]=0; 220 for(i=0;i<UALG.vexnum;i++) 221 if(!visit[i]){ 222 visit[i]=1; 223 printf("%c\n",UALG.vertices[i].data); 224 q.push(i); 225 while(!q.empty()) 226 { 227 v=q.front(); 228 q.pop(); 229 p=UALG.vertices[v].firstarc; 230 while(p) 231 { 232 if(!visit[p->adjvex]) 233 { 234 visit[p->adjvex]=1; 235 printf("%c\n",UALG.vertices[p->adjvex].data); 236 q.push(p->adjvex); 237 } 238 p=p->nextarc; 239 } 240 241 242 } 243 244 } 245 246 } 247 248 249 250 void prim(MGraph G,char v) 251 {//用prim算法求最小生成树 252 int i,j,k,min,n; 253 k=locatevex(G,v); 254 for(i=0;i<G.vexnum;i++) 255 { 256 if(i!=k) 257 { 258 259 closedge[i].adjvex=v; 260 closedge[i].lowcost=G.arc[k][i].adj; 261 262 } 263 } 264 closedge[k].lowcost=0; 265 for(i=1;i<G.vexnum;i++) 266 { 267 min=INFINITY; 268 269 for(j=0;j<G.vexnum;j++) 270 { 271 if(closedge[j].lowcost!=0&&closedge[j].lowcost<min) 272 { 273 n=j; 274 min=closedge[j].lowcost; 275 } 276 } 277 printf("%c %c\n",closedge[n].adjvex,G.vex[n]); 278 closedge[n].lowcost=0; 279 for(j=0;j<G.vexnum;j++) 280 if(G.arc[n][j].adj<closedge[j].lowcost&&G.arc[n][j].adj!=INFINITY) 281 { 282 closedge[j].adjvex=G.vex[n]; 283 closedge[j].lowcost=G.arc[n][j].adj; 284 } 285 286 287 } 288 printf("\n"); 289 290 291 } 292 int indegree[max_vertex_num]; 293 int topsort(ALGraph ALG,ALGraph InsertALG) 294 {//拓扑排序 295 ArcNode *p; 296 stack<int>s; 297 int i,k,count; 298 for(i=0;i<ALG.vexnum;i++) 299 { 300 InsertALG.vertices[i].count=0; 301 for(p=InsertALG.vertices[i].firstarc;p!=NULL;p=p->nextarc) 302 InsertALG.vertices[i].count++; 303 } 304 for(i=0;i<ALG.vexnum;i++) 305 { 306 indegree[i]=InsertALG.vertices[i].count; 307 printf("%d\n",indegree[i]); 308 } 309 310 for(i=0;i<ALG.vexnum;i++) 311 if(indegree[i]==0) 312 s.push(i); 313 count=0; 314 while(!s.empty()) 315 { 316 317 i=s.top(); 318 s.pop(); 319 printf("%c ",ALG.vertices[i].data); 320 count++; 321 for(p=ALG.vertices[i].firstarc;p;p=p->nextarc) 322 { 323 k=p->adjvex; 324 indegree[k]--; 325 if(indegree[k]==0) 326 s.push(k); 327 } 328 329 330 } 331 if(count<ALG.vexnum) 332 return -1; 333 else 334 return 1; 335 336 337 } 338 339 void short_dij(MGraph G,int v0,int *P,int *D) 340 {//用dij球最短路径 341 int i,v,w,min; 342 for(i=0;i<G.vexnum;i++) 343 { 344 finial[i]=0; 345 D[i]=G.arc[v0][i].adj; 346 if(D[i]<INFINITY) 347 P[i]=v0; 348 } 349 D[v0]=0;finial[v0]=1; 350 for(i=1;i<G.vexnum;i++) 351 { 352 min=INFINITY; 353 for(w=0;w<G.vexnum;w++) 354 { 355 if(finial[w]==0) 356 if(D[w]<min) 357 { 358 v=w; 359 min=D[w]; 360 } 361 } 362 if(min<INFINITY) 363 finial[v]=1; 364 else 365 break; 366 for(w=0;w<G.vexnum;w++) 367 { 368 if(finial[w]==0&&min+G.arc[v][w].adj<D[w]) 369 { 370 D[w]=min+G.arc[v][w].adj; 371 P[w]=v; 372 printf("%d ",P[w]); 373 } 374 375 } 376 printf("\n"); 377 378 } 379 printf("路径长度为:\n"); 380 for(i=0;i<G.vexnum;i++) 381 { 382 if(D[i]==INFINITY) 383 printf("无法到达!!!\n"); 384 else 385 printf("%d\n",D[i]); 386 } 387 388 } 389 390 int main() 391 { 392 int menu; 393 char V; 394 395 do{ 396 void print(); 397 scanf("%d",&menu); 398 switch(menu) 399 { 400 case 1: CreateALGraph(ALG,InsertALG);break; 401 case 2: shuchu(ALG); break; 402 case 3: CreateALGraph(ALG,InsertALG);Degree( ALG, InsertALG);break; 403 case 4: CreateALGraph(ALG,InsertALG);topsort( ALG,InsertALG);break; 404 case 5: CeratUALGraph(UALG);DFSTraverse(UALG);break; 405 case 6: CeratUALGraph(UALG);BFSTraverse(UALG);break; 406 case 7: CreateUDN(G,1);printf("请输入出发顶点:\n");scanf("%c",&V);prim(G,V);break; 407 case 8: CreateUDN(G,0);short_dij( G, 0,P,D);break; 408 case 0: return 0; 409 } 410 }while(menu!=0); 411 return 0; 412 }
七、排序的基本操作
1 // 实验八:排序的基本操作 2 3 输入一组关键字序列分别实现下列排序: 4 (1)实现简单选择排序、直接插入排序和冒泡排序。 5 (2)实现希尔排序算法。 6 (3)实现快速排序算法。 7 (4)实现堆排序算法。 8 (5)采用链式存储实现简单选择排序、直接插入排序和冒泡排序。 9 (6)在主函数中设计一个简单的菜单,分别测试上述算法。 10 11 综合训练:采用几组不同数据测试各个排序算法的性能(比较次数和移动次数)。 12 13 14 # include <stdio.h> 15 # include <stdlib.h> 16 17 #define MAXSIZE 20 18 typedef int KeyType; 19 20 typedef struct 21 { 22 KeyType key; 23 //InfoType otherinfo; 24 }RedType; 25 typedef struct 26 { 27 RedType r[MAXSIZE+1]; 28 int length; 29 }SqList; 30 31 typedef SqList HeapType; 32 33 typedef struct Node 34 { 35 int data; 36 struct Node * pNext; 37 }Node, *pNode; 38 39 void printMenu(); 40 void InsertSort(SqList &); 41 bool LT(int ,int ); 42 void traverse(SqList &); 43 void SelectSort(SqList &); 44 int SelectMinKey(SqList &, int); 45 void BubbleSort(SqList &); 46 void ShellSort(SqList &L, int dlta[], int t); 47 void ShellInsert(SqList &L, int); 48 void Qsort(SqList &, int ,int); 49 int Partition(SqList &, int ,int); 50 void HeapSort(HeapType &); 51 void HeapAdjust(HeapType &, int ,int ); 52 void Ltraverse(pNode &); 53 void LSelectSort(pNode &); 54 pNode LSelectMinkey(pNode &); 55 void LBubbleSort(pNode &); 56 57 int main() 58 { 59 int n; 60 SqList L; 61 pNode pHead, p, q; 62 if( !(pHead=(pNode)malloc(sizeof(Node)) )) 63 exit (-1); 64 pHead->pNext = NULL; 65 int dlta[99] = {3, 2, 1}; 66 printf("请输入数组长度L.length = "); 67 scanf("%d", &L.length); 68 p = pHead; 69 for(int i=1; i<=L.length; i++) 70 { 71 scanf("%d", &L.r[i].key); 72 if( !(q = (pNode)malloc(sizeof(Node)))) 73 exit (-1); 74 q->data = L.r[i].key; 75 p->pNext = q; 76 p = q; 77 } 78 p->pNext = NULL; 79 80 81 printMenu(); 82 while(scanf("%d", &n)!=EOF) 83 { 84 switch(n) 85 { 86 case 1: 87 SelectSort(L); 88 printf("---排序后的数组为:"); 89 traverse(L); 90 break; 91 case 2: 92 InsertSort(L); 93 printf("---排序后的数组为:"); 94 traverse(L); 95 break; 96 case 3: 97 BubbleSort(L); 98 printf("---排序后的数组为:"); 99 traverse(L); 100 break; 101 case 4: 102 ShellSort(L, dlta, 2); 103 printf("---排序后的数组为:"); 104 traverse(L); 105 break; 106 107 case 5: 108 109 Qsort(L, 1, L.length); 110 printf("---排序后的数组为:"); 111 traverse(L); 112 break; 113 case 6: 114 HeapSort(L); 115 printf("---排序后的数组为:"); 116 traverse(L); 117 break; 118 case 7: 119 LSelectSort(pHead); 120 Ltraverse(pHead); 121 break; 122 123 case 8: 124 BubbleSort(L); 125 traverse(L); 126 break; 127 case 9: 128 LBubbleSort(pHead); 129 Ltraverse(pHead); 130 break; 131 132 default: 133 printf("---输入有误,请重新输入!!---\n"); 134 } 135 printMenu(); 136 } 137 138 139 return 0; 140 } 141 142 void printMenu() 143 { 144 printf("------排序菜单如下------\n"); 145 printf("1.简单选择排序\n"); 146 printf("2.直接插入排序\n"); 147 printf("3.冒泡排序\n"); 148 149 printf("4.希尔排序\n"); 150 printf("5.快速排序\n"); 151 printf("6.堆排序\n"); 152 printf("7.链式存储实现简单选择排序\n"); 153 printf("8.链式存储实现简单直接插入排序\n"); 154 printf("9.链式存储实现简单冒泡排序\n"); 155 printf("---请选择排序方式:"); 156 } 157 158 void InsertSort(SqList &L) 159 { 160 int i, j; 161 for( i=2; i<=L.length; i++) 162 if(LT(L.r[i].key, L.r[i-1].key)) 163 { 164 L.r[0] = L.r[i]; 165 L.r[i] = L.r[i-1]; 166 for( j=i-2; LT(L.r[0].key, L.r[j].key); --j) 167 L.r[j+1] = L.r[j]; 168 L.r[j+1] = L.r[0]; 169 } 170 } 171 172 bool LT(int a,int b) 173 { 174 if( a>=b ) 175 return false; 176 else 177 return true; 178 } 179 180 void traverse(SqList &L) 181 { 182 for( int i=1; i<=L.length; i++) 183 printf("%d ", L.r[i].key); 184 printf("\n\n"); 185 } 186 187 void SelectSort(SqList &L) 188 { 189 int i, j; 190 RedType t; 191 for( i=1; i<=L.length; i++) 192 { 193 j = SelectMinKey(L, i); 194 if( i!=j) 195 { 196 t = L.r[i]; 197 L.r[i] = L.r[j]; 198 L.r[j] = t; 199 } 200 } 201 } 202 203 int SelectMinKey(SqList &L, int j) 204 { 205 int min, k; 206 k = j; 207 min = L.r[k].key; 208 for(int i=j; i<=L.length; i++) 209 { 210 if( L.r[i].key<min ) 211 { 212 min = L.r[i].key; 213 k = i; 214 } 215 } 216 return k; 217 } 218 219 void BubbleSort(SqList &L) 220 { 221 int i, j; 222 RedType t; 223 for( i=1; i<L.length; i++) 224 for( j=i+1; j<=L.length; j++) 225 { 226 if(L.r[i].key > L.r[j].key) 227 { 228 t = L.r[i]; 229 L.r[i] = L.r[j]; 230 L.r[j] = t; 231 } 232 } 233 } 234 235 void ShellSort(SqList &L, int dlta[], int t) 236 { 237 int k; 238 for(k=0; k<t; k++) 239 ShellInsert(L, dlta[k]); 240 } 241 242 void ShellInsert(SqList &L, int dk) 243 { 244 int i, j; 245 for( i=dk+1; i<=L.length; i++) 246 if(LT(L.r[i].key, L.r[i-dk].key)) 247 { 248 L.r[0] = L.r[i]; 249 for(j=i-dk; j>0 && LT(L.r[0].key, L.r[j].key); j-=dk) 250 L.r[j+dk] = L.r[j]; 251 L.r[j+dk] = L.r[0]; 252 } 253 } 254 255 void Qsort(SqList &L, int low, int high) 256 { 257 int pivotloc; 258 if(low<high) 259 { 260 pivotloc = Partition(L, low, high); 261 Qsort(L, low, pivotloc-1); 262 Qsort(L, pivotloc+1, high); 263 } 264 } 265 266 int Partition(SqList &L, int low,int high) 267 { 268 int pivotkey; 269 L.r[0] = L.r[low]; 270 pivotkey = L.r[low].key; 271 while(low<high) 272 { 273 while(low<high && L.r[high].key>=pivotkey) 274 --high; 275 L.r[low] = L.r[high]; 276 while(low<high && L.r[low].key<=pivotkey) 277 ++low; 278 L.r[high] = L.r[low]; 279 } 280 L.r[low] = L.r[0]; 281 return low; 282 } 283 284 void HeapSort(HeapType &H) 285 { 286 int i; 287 RedType t; 288 for( i = H.length/2; i>0; i--) 289 HeapAdjust( H, i, H.length ); 290 for( i = H.length; i>1; i--) 291 { 292 t = H.r[1]; 293 H.r[1] = H.r[i]; 294 H.r[i] = t; 295 HeapAdjust(H, 1, i-1); 296 } 297 } 298 299 void HeapAdjust(HeapType &H, int s,int m) 300 { 301 int j; 302 RedType rc; 303 rc = H.r[s]; 304 for( j=2*s; j<=m; j*=2) 305 { 306 if( j<m && LT(H.r[j].key, H.r[j+1].key) ) 307 j++; 308 if( !LT(rc.key, H.r[j].key) ) 309 break; 310 H.r[s] = H.r[j]; 311 s = j; 312 } 313 H.r[s] = rc; 314 } 315 316 void Ltraverse(pNode &pHead) 317 { 318 pNode p; 319 p = pHead->pNext; 320 while( NULL != p) 321 { 322 printf("%d ", p->data); 323 p = p->pNext; 324 } 325 printf("\n"); 326 } 327 328 void LSelectSort(pNode &pHead) 329 { 330 pNode p, q; 331 int t; 332 q = (pNode)malloc(sizeof(Node)); 333 for( p = pHead->pNext->pNext; NULL != p->pNext; p = p->pNext) 334 { 335 q = LSelectMinkey( p ); 336 if( p->data != q->data) 337 { 338 t = p->data; 339 p->data = q->data; 340 q->data = t; 341 } 342 } 343 } 344 345 pNode LSelectMinkey(pNode &p) 346 { 347 pNode q; 348 q = p; 349 int min; 350 min = q->data; 351 while( p != NULL) 352 { 353 if( p->data < min) 354 { 355 min = p->data; 356 q = p; 357 } 358 p = p->pNext; 359 } 360 361 return q; 362 } 363 364 void LBubbleSort(pNode &pHead) 365 { 366 int t; 367 pNode p,q; 368 //RedType t; 369 for( p=pHead->pNext; p->pNext->pNext != NULL; p = p->pNext) 370 for( q=p->pNext; q->pNext!=NULL; q=q->pNext) 371 { 372 if(p->data > q->data) 373 { 374 t = p->data; 375 p->data = q->data; 376 q->data = t; 377 } 378 } 379 }