城市链表(设计性实验)

城市链表(设计性实验)

1. 需求分析

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

  1. 给定一个城市名,返回其位置坐标。
  2. 给定一个位置坐标P和一个距离D,返回所有与P的距离小于等于D的城市。
    分析:
  3. 输入的形式和输入值的范围:按照提示放好数据文件后,输入Y,根据屏幕提示,输入想要的功能对应的数字,根据屏幕提示输入对应数据,输入坐标数据为float型,输入城市名可为中文。
  4. 输出的形式:查找城市坐标返回两个float型的数据,给定距离查找城市返回数个城市名。
  5. 程序所能达到的功能:
    i. 给定一个城市名,返回其位置坐标。
    ii. 给定一个位置坐标P和一个距离D,返回所有与P的距离小于等于D的城市。
  6. 测试数据:
    · 按照屏幕提示将数据放入对应文件中,输入y;
    · 输入1,再输入广州,输出广州的坐标;
    · 输入2,输入坐标120 25,输入距离50,输出数个城市;
    · 输入3,退出;

2. 概要设计

  1. 为了实现程序功能,需要定义顺序栈的抽象数据类型。
ADT List { 
数据对象: D={ ai | ai ∈ElemSet, i=1,2,...,n, n≥0 } 
数据关系: R1={ <ai-1, ai >|ai-1, ai∈D, i=2,...,n } 
typedef struct lnote{      //城市链表结构节点 
	float x;
	float y;
	char name[100];
	struct lnote *next;
}*node,NODE;
typedef struct LIST{         //城市链表结构 
	node head;
	node tail;
	int len;
}list;
基本操作:
初始化操作 InitList( &L )
	操作结果:构造一个空的线性表L。 
结构销毁操作 DestroyList( &L ) 
初始条件:线性表 L 已存在。
	操作结果:销毁线性表 L。
线性表判空操作 ListEmpty( L )
	初始条件:线性表 L 已存在。
	操作结果:若 L 为空表,则返回 TRUE,否则返回FALSE。
求线性表的长度 ListLength( L )
	初始条件:线性表 L 已存在。
	操作结果:返回 L 中数据元素的个数。
求数据元素的前驱 PriorElem( L, cur_e, &pre_e )
	初始条件:线性表 L 已存在。
	操作结果:若 cur_e 是 L 的元素,则用pre_e 返 回它的前驱,否则操作失	败,pre_e无 定义。
求数据元素的后继 NextElem( L, cur_e, &next_e )
	初始条件:线性表 L 已存在。
	操作结果:若 cur_e 是 L 的元素,则用next_e 返 回它的后继,否则操作失败,next_e 无定义。
求线性表中第i个数据元素 GetElem( L, i, &e )
	初始条件:线性表 L 已存在,并且 1≤i≤ListLength(L) 。
	操作结果:用 e 返回 L 中第 i 个数据元素的值。
定位函数 LocateElem( L, e, compare( ) )
	初始条件:线性表 L 已存在,e 为给定值, compare( ) 是元素判定函数。
	操作结果:返回 L 中第 1 个与 e 满足关系 compare( ) 的元素的位序。 若这样的元素不存在,则返回值为 0。
遍历线性表 ListTraverse(L, visit( ))
	初始条件:线性表 L 已存在。 visit( ) 为某个访问函数。
	操作结果:依次对 L 中每个元素调用 函数visit( )。一旦 visit( )失败, 则操作失败。
线性表置空 ClearList( &L )
	初始条件:线性表 L 已存在。
	操作结果:将 L 重置为空表。
改变第 i 个数据元素的值 PutElem( &L, i, e )
	初始条件:线性表 L 已存在,并且 1≤i≤ListLength(L) 。
	操作结果:L 中第 i 个元素赋值 e 。
插入数据元素 ListInsert( &L, i, e )
	初始条件:线性表 L 已存在,且 1≤i≤ListLength(L)+1 。
	操作结果:在 L 中的第 i 个元素之前插入 新的元素 e,L 的长度增1。
删除数据元素 ListDelete( &L, i, &e )
	初始条件:线性表 L 已存在并且非空, 且1≤i≤ListLength(L) 。
	操作结果:删除 L中的第 i 个元素,并且用 e 返 回其值,L 的长度减1} ADT List

3.具体代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define ERROR 0
#define OK 1 

typedef struct lnote{      //城市链表结构节点 
	float x;//城市位置x坐标 
	float y;//城市位置y坐标 
	char name[100];//城市名字 
	struct lnote *next;//链表的指针 
}*node,NODE;
typedef struct LIST{         //城市链表结构 (获取必要的信息) 
	node head;//头指针 
	node tail;//尾指针 
	int len;//长度 
}list;

void createlist(list *p);                            //创建线性表
void add_node(list *p,char *a,float x,float y);      //添加节点
void find_node(list p,char *a);                      //查找节点
void scope_for(float p_x,float p_y,float d,list p);  //给定坐标找城市

int main()
{
	FILE *data;//创建文件指针 
	list city;//创建城市链表 
	int sum;//
	char judge; 
	createlist(&city);//初始化城市链表 
	printf("请将数据依次放入文件'城市链表.txt.'\n格式如下:\n名称\n坐标\n");
	printf("是否放入?(Y/N)");
	scanf("%c",&judge);//用于判断输入的是否为Y 
	while(judge != 'Y'&&judge != 'y')//不区分大小写 
	{
	    printf("请将数据放入文件'城市链表.txt.'\n");                                    
	    printf("是否放入?(Y/N)");
		getchar();
	    scanf("%c",&judge);
	}//循环,一直到输入为Y 
	if((data=fopen("城市链表.txt","rt"))==NULL)
	{
		exit(-1);//如果无法打开,则错误 
	}
	char a[50]; 
	for(;(fscanf(data,"%s",a))!=EOF;)//先将 城市名储存到数组a中 
	{
		float x,y;//定义X,Y坐标 
		fscanf(data,"%f %f",&x,&y);//读取城市的坐标,分别放在x,y变量中 
		add_node(&city,a,x,y);//将该城市的信息(名字,坐标放入节点中) 
		memset(a,0,sizeof(a));//清空数组的信息,便于下一次循环 
	}
	do
	{
		int select;//用于存放选择的信息 
	    printf("\n请选择:\n1.由城市名查找坐标 2.给定坐标和距离查找城市 3.退出:");
		scanf("%d",&select);
		switch(select)//开关 
		{
		    case 1:
		    	//由城市名查找坐标
		    {
					
	    		getchar(); //先输入城市名 
	            char a[50];
	            printf("\n请输入城市名:");
	            scanf("%s",&a[0]);//将城市名存在数组a中 
	            find_node(city,a);//查找节点 
			    break;
			}
			case 2:
				//给定坐标和距离查找城市
			{
				float x,y,r;//分别存放坐标和距离 
	            printf("请输入坐标:");
	            scanf("%f %f",&x,&y);
	            printf("请输入距离:");
	            scanf("%f",&r);
	            scope_for(x,y,r,city);//查询城市		
				break;	
			}
			default:
			    return 0;	
		}	
	}while(1);
	return 0;
}

void createlist(list *p)                           //创建线性表
{
	p->head = malloc(sizeof(NODE));//分配存储空间 
	if(!p->head)
	{
		exit(ERROR);//如果没有储存空间,退出 
	}
	p->head->next = NULL;//先给头指针指向的元素赋值null 
	p->tail = p->head; //尾指针=头指针 
	p->len=0;//初始长度为0 
}

void add_node(list *p,char *a,float X,float Y)     //添加节点 
{
	node q;
	q = malloc(sizeof(NODE));
	q->x = X;
	q->y = Y;
	strcpy(q->name,a);
	q->next = NULL;
	p->tail->next = q;
	p->tail = q;
	p->len++;
}
void find_node(list p,char *a)                //查找节点 
{
	node q;//先创建一个节点指针 
	q = p.head->next;//指向第一个节点 
	int i = 0;//用于for循环 
	for(;++i <= p.len;q = q->next)//循环遍历 
	{
		if(!strcmp(q->name,a))//如果两个字符串匹配,则返回0,大于返回正,小于返回负 
		{
			//成功匹配,输出 
			printf("位置(纬度 经度):%f %f",q->x,q->y);
			break;
		}
	}
	if(!q)
	{
		printf("未找到查询的城市");
	}
}
void scope_for(float p_x,float p_y,float d,list p)   //给定坐标找城市 
{
	node q;//定义节点指针 
	int judge=ERROR;//先使判断变量为error 
	q = p.head->next;//把q指向链表的第一个节点 
	int i = 0;//用于for循环 
	for(;++i <= p.len;q = q->next)
	{
		//循环遍历 
		if(((q->x-p_x)*(q->x-p_x)+(q->y-p_y)*(q->y-p_y)-d*d) <= 0)  //城市与坐标之间距离小于给定距离 
		{
			judge=OK;//使得之后的判断 
			printf("%s ",q->name);//输出城市名称 
		}
	}
	if(!judge)
	{
		printf("未找到符合条件的城市");
	}
}

4.相关文件

城市链表.txt

北京
116.41667 39.91667
上海
121.43333 34.50000
天津
117.20000 39.13333
香港
114.10000 22.20000
广州
113.23333 23.16667
杭州
120.20000 30.26667
重庆市
106.45000 29.56667
福州
119.30000 26.08333
兰州
103.73333 36.03333
贵阳
106.71667 26.56667
长沙
113.00000 28.21667
南京
118.78333 32.05000
南昌
115.90000 28.68333
沈阳
123.38333 41.80000
太原
112.53333 37.86667
成都
104.06667 30.66667
拉萨
91.00000 29.60000
乌鲁木齐
87.68333 43.76667
昆明
102.73333 25.05000
西安
108.95000 34.26667
西宁
101.75000 36.56667
银川
106.26667 38.46667
哈尔滨
126.63333 45.75000
长春
125.35000 43.88333
武汉
114.31667 30.51667
郑州
113.65000 34.76667
石家庄
114.48333 38.03333
海口
110.35000 20.01667
澳门
113.50000 22.20000
合肥 
31.52 117.17
太原 
37.54 112.33
孝义 
37.08 111.48
  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值