当前位置:   article > 正文

实验报告:城市链表问题和约瑟夫环_[问题描述] 将若干城市的信息,存入一个带头结点的单链表。结点中的城市信息包括:

[问题描述] 将若干城市的信息,存入一个带头结点的单链表。结点中的城市信息包括:

  • 实验目的
  1. 本次实验的主要目的在于熟悉线性表的基本运算在两种存储结构上的实现,其中以熟悉各种链表的操作为侧重点。
  2. 熟悉线性表在软件工程项目中数据存储和处理中的运用。
  • 实验内容
  1. 城市链表

[问题描述]

将若干城市的信息,存入一个带头结点的单链表。结点中的城市信息包括:城市名,城市的位置坐标。要求能够利用城市名和位置坐标进行有关查找、插入、删除、更新等操作。

[基本要求]

  (1) 给定一个城市名,返回其位置坐标;

  (2) 给定一个位置坐标P和一个距离D,返回所有与P的距离小于等于D的城市。

[测试数据]

由学生依据软件工程的测试技术自己确定。注意测试边界数据。

  1. 约瑟夫环

[问题描述]

约瑟夫(Joeph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,

每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。

[基本要求]

利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

[测试数据]

  m的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。

[实现提示]

程序运行后首先要求用户指定初始报数上限值,然后读取各人的密码。设n≤30。

  • 实验环境

Dev C++

  • 实验过程和实验结果

问题分析与设计方案:

  1. 分析每个结点的结构体里应该包含的元素:城市名字,经纬度
  2. 打印信息:注意排版提高美观增强用户观赏性
  3. 实现查找功能(注意健壮性)
  4. 利用数学库封装出距离比较函数

  1. #include <stdio.h>
  2. #include  <stdlib.h>
  3. #include <string.h>
  4. #include <math.h> 
  5. #define OK 1
  6. #define ERROR 0 
  7. typedef int Status ; 
  8. typedef struct LNode{
  9.  
  10.  char name[200] ;      //存储城市名; 
  11.  float x, y ; //存储城市坐标; 
  12.  struct LNode *next ;
  13.  
  14. }LNode, *LinkList;
  15. //创建一个链表 
  16. LinkList CreatList (int n) {
  17.  LinkList l, tmp, p ;
  18.  l = (LinkList)malloc(sizeof(LNode)) ;
  19.  l->next = NULL ;
  20.  
  21.  tmp = l ;
  22.  
  23.  int i = 0;
  24.  for(i = 0 ; i < n ; i ++) {  //向链表中存储数据 
  25.   p = (LinkList)malloc(sizeof(LNode)) ;
  26.   scanf("%s %f %f", &p->name, &p->x, &p->y) ;
  27.   p->next = tmp->next ;
  28.   tmp->next = p ;
  29.   tmp = p ;
  30.  }
  31.  return l ;
  32. }
  33. //打印出链表的信息
  34. Status Display(LinkList l) {
  35.  LinkList p ;
  36.  p = l ;
  37.  p = p->next ;
  38.   printf("\n\n") ;
  39.   printf("城市信息为:") ; 
  40.   printf("\n") ;
  41.   printf("-----------------------------------------------\n") ;
  42.   printf("序号\t城市名称\t城市坐标\n", p->name, p->x, p->y) ;  
  43.  int order = 1 ;  
  44.  while(p) {
  45.   printf("%02d\t %-8s\t( %.2f°N, %.2f°E )\n",order, p->name, p->x, p->y) ;
  46.   p = p->next ;
  47.   order++ ;
  48.  }
  49.   printf("-----------------------------------------------\n\n" ) ; 
  50.   return OK ;
  51. //查找一个链表元素
  52. LinkList SearchList(LinkList l){ 
  53.  LinkList q ;
  54.  q = (LinkList)malloc(sizeof(LNode)) ;
  55.  q->next = NULL ;
  56.  scanf("%s", &q->name) ;
  57.  LinkList p ;
  58.  p = l ;
  59.  while(p) {
  60.   p = p->next ;
  61.   if(!strcmp(p->name, q->name)){
  62.    return p ; 
  63.   }
  64.   if(p->next == NULL){
  65.   printf("没有录入此地区信息,系统关闭") ;
  66.      return NULL ;
  67.      break ;
  68.   }
  69.  }  
  70. }
  71. //进入城市距离计算比较功能
  72. LinkList DistanceCity(LinkList l, float e){
  73.  printf("请输入一个城市的名称作为定位标志:\n") ;
  74.  LNode *index , *p, *q;
  75.  index = SearchList(l) ;
  76.  
  77.  //计算列表中其他城市与定位城市的距离
  78.  int i = 0 ; 
  79.  float dx = 0 , dy = 0 ;
  80.  float distance = 0 ;
  81.  LinkList dis ; //距离小于给定值的城市的所有信息存储在此链表 ;
  82.  LNode *d ; //一直指向dis链表末尾的指针
  83.  dis = (LinkList)malloc(sizeof(LNode)) ;
  84.  dis->next = NULL ;
  85.  d = dis ; 
  86.   
  87.  q = l ; //利用两个坐标点间的距离公式,开始计算 
  88.  while(q){
  89.   q = q->next ;
  90.   dx = q->x - index->x ;
  91.   dy = q->y - index->y ;
  92.   distance = sqrt(dx * dx + dy * dy) ;
  93.   printf("%-8s%-8s的距离为%.2f\n",q->name, index->name, distance) ;
  94.   if(distance <= e) {
  95.    LinkList temp ;
  96.    temp = (LinkList)malloc(sizeof(LNode)) ;
  97.    strcpy(temp->name , q->name) ;
  98.    temp->x = q->x ;
  99.    temp->y = q->y ;
  100.    temp->next = d->next ;
  101.    d->next = temp ;
  102.    d = temp ;
  103.   }
  104.   if(q->next == NULL)
  105.   Display(dis) ;
  106.  } 
  107.     return dis ; 
  108. Status Entrance(char c, LinkList l ){ 
  109.  //查找城市信息  
  110.   if(c == 'A' || c == 'a') {
  111.  LNode *index ;
  112.  printf("请输入希望查询的城市:") ;
  113.  index = SearchList(l) ;
  114.     printf(" ( %.2f°N, %.2f°E )",  index->x, index->y) ;
  115. }
  116.    
  117.  //进入城市距离计算比较功能
  118.  if(c == 'B' || c =='b') {
  119.  float n ;
  120.  printf("输入查询的距离范围:\n") ;
  121.  scanf("%f", &n) ; 
  122.  LinkList l_1 ; 
  123.  l_1 = DistanceCity(l,n);
  124.  Display(l_1) ;
  125.  }
  126.  
  127.  return OK ;
  128. }
  129. int main() {   
  130.  printf("建立城市链表ing\n") ;
  131.  int e = 0 ;
  132.  printf("请输入城市数目:") ;
  133.  scanf("%d", &e) ;
  134.  
  135.  //创建一个城市链表 
  136.  LinkList l ;
  137.  printf("请批量输入城市名及经纬坐标(例:a 120 12 b 23 45 c 12 32):\n") ;
  138.  l = CreatList(e) ;
  139.  Display(l) ;
  140.  
  141.  //入口 
  142.  printf("操作菜单\n") ;
  143.  printf("A.查找城市信息\n") ;
  144.  printf("B.查找一定距离内的所有城市\n") ;
  145.  printf("C.退出操作\n") ;
  146.  while(1){
  147.  char c ; 
  148.  printf("\n请输入操作数:\n") ;
  149.     scanf("%s", &c) ;
  150.     if(c == 'C' || c == 'c'){
  151.     printf("退出程序。\n") ; 
  152.  break ; // 退出程序 
  153. }
  154.     Entrance(c, l) ;
  155.     }
  156.   
  157.  return 0 ;
  158. }

问题分析与设计方案:

        1. 分析每个结点的结构体里应该包含的元素:包括所在位置(最开始的时候没有考虑到和单链表不同而没有设置,走了一些弯路)和密码
        2. 打印环形链表(也作为检验措施帮助调试)
        3. 实现每次出列更改密码操作
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. typedef struct node {
  4.  int num;  //num为人的顺序
  5.  int data;  //data为人所带的密码
  6.  struct nodenext;
  7. } node, * Linklist;
  8. void Initlist(Linklist* L) {
  9.  (*L) = (Linklist)malloc(sizeof(node));
  10.  (*L)->next = (*L);
  11. }
  12. void CreateList(Linklist* L, int n) {
  13.  node* s, * r;
  14.  r = *L;
  15.  int i;
  16.  while (n--) {
  17.   s = (Linklist)malloc(sizeof(node));
  18.   printf("请输入人的位置和密码:");
  19.   scanf("%d%d", &s->num, &s->data);
  20.   r->next = s;
  21.   r = s;
  22.  }
  23.  r->next = (*L)->next;      //让尾节点指向首节点 
  24. }
  25. void print(Linklist L, int n, int m) {
  26.  Linklist p, r;
  27.  p = L;
  28.  r = L->next;
  29.  printf("出列顺序:");
  30.  while (n--)
  31.  {
  32.   for (int j = 1; j < m; j++)    //循环m-1次后后继节点就是要删除的节点!!
  33.   {
  34.    p = r;
  35.    r = r->next;
  36.   }
  37.   printf("%2d", r->num);
  38.   p->next = r->next;
  39.   m = r->data;
  40.   free(r);
  41.   r = p->next;
  42.  }
  43. }
  44. int main() {
  45.  int n;
  46.  int m;
  47.  printf("初始报数上限值:");
  48.  scanf("%d", &m);           //第一个开始密码
  49.  Linklist L;
  50.  Initlist(&L);
  51.  printf("请输入人数大小:");
  52.  scanf("%d", &n);
  53.  CreateList(&L, n);
  54.  print(L, n, m);
  55.  return 0;
  56. }

  • 实验心得
  1. 巩固了C语言和C++的知识点,对指针的理解更进一步:指针调用结构体内的变量是高效,在初次学习C语言的时候并未理解透彻
  2. 基本掌握了链表的知识点,熟练掌握了链表的增、删、查:但链表的简单八股文基本能够熟练操作了,但是针对每个题目而异的部分还需要反复思考,不能很快写出。
  3. 对于用户交互界面的设计更加友好:oj风格的输入输出便于机器检查,但不利于自己和他人阅读,在和同学的交流过程中需要增加一些交互式的设计包括一些提示,有助于下次阅读代码时能够快速理解
  4. 对于边界的调试更加细致:在实际写代码的时候链表中间的步骤本身不是难点,但是在初始化第一位元素和检验边界条件的时候往往有很多的bug。这时可以使用debug对一些函数里的元素进行观测。另一方面也可以通过“打印”的方式来检验。在进行实验构成中,建立的Display函数往往最大的作用不是打印出这个链表本身,而是在循环过程中反复打印,帮助理解每次循环赋值后内部结构到底是什么样子的。
  5. 对于编译器本身有了更好的理解:在实验过程中尝试了多种编译器,对包括不同版本dev c++会遇到的因版本不同而产生的bug有了一定的理解。
  6. 忘记free导致指针重复写入出现报错
  7. 注意代码健壮性,把一些由于用户输入不当产生的错误做好提前的预防和解决措施(包括用户输入选项时候输入的大小写同时设置提高使用效果)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/775466
推荐阅读
相关标签
  

闽ICP备14008679号