公交换乘系统c语言,公交换乘的简单实现(源码)

最初是做2004年某期《程序员》杂志上的一道题,叫“洞穴探险”,结果写着写着就做到公交换乘的思路上去了。看来做GIS做久了,都成习惯了。后来工作忙,就扔下了。最近翻看以前自娱自乐时写的东东,看到了这段代码,索性贴出来共享,抛砖引玉吧。

文中使用的queue_alloc和queue_free函数是洒家自己设计的“简易空间配置器”的C 语言实现版本,关于简易空间配置器的详细信息,请参考《简易空间配置器》(http://blog.csdn.net/bfbd/archive/2004/06/22/22743.aspx)一文。

#include "stdafx.h"

#include

#include

#include

using namespace std;

const _BUF_SIZE_ = 100;

// C版本的搜索函数

extern "C"

{

typedef struct Q_NODE

{

int id;    //节点编码

Q_NODE *father;  //父节点的地址

} Q_NODE;

/*

队列由多段缓冲区组成,每段缓冲区为连续的多个节点。

id大于0时表示节点的编码值。

father为正常的内存地址时表示本节点的父节点所在的内存

id为0表示当前节点为缓冲区末尾节点,其father指向下一个缓冲区段的起点。

father为空表示当前节点为队列末尾节点

father为-1表示当前节点为树的根节点

*/

void dumpMap(int n, int *ph, int *pl)

{

int _i;

printf("ph[]: ");

for (_i=0; _i

printf("%d ", ph[_i]);

printf("\n");

printf("pl[]: ");

for (_i=0; _i

printf("%d ", pl[_i]);

printf("\n");

}

void dumpDeep(int n, int *pd)

{

int _i;

printf("pd[]: ");

for (_i=0; _i

printf("%d ", pd[_i]);

printf("\n");

}

void dumpQueue(Q_NODE *Qs)

{

Q_NODE *_pQ;

printf("Q: ");

for ( _pQ=Qs; (_pQ->father && _pQ->id); _pQ++ )

{

printf("%d->%d ", _pQ->id,

((-1!=(int)_pQ->father) && (_pQ->father)) ? (_pQ->father->id) : 0);

if ( 0==_pQ->id )

_pQ = _pQ->father;

}

printf("\n");

}

Q_NODE* queue_alloc(int size)

// 为队列申请新的空间

// size: 申请的空间大小

// return: 申请空间的起始地址

{

Q_NODE *Qb = new Q_NODE[size];

//初始化对列缓冲区

memset(Qb, 0, sizeof(Q_NODE) * size);

for (int i = 0; i < size - 1; i++)

Qb[i].father = &(Qb[i+1]);

Qb[size-1].father = NULL;

return Qb;

}

void queue_free(Q_NODE* pQ, int size)

// 释放对列所占的内存

// pQ: 队列起始地址

// return:

{

if (NULL != pQ)

{

Q_NODE* p;

while (NULL != pQ)

{

p = pQ;

pQ = pQ[size-1].father;

delete[] p;

}

}

}

void search_change(int n, int *ph, int *pl, int *pd)

// 搜索换乘路径

// n: 节点个数

// *ph: 邻接压缩表描述序列(长度为n+1)

// *pl: 邻接压缩表序列(长度为ph[n])

// *pd: 换乘深度(长度为n+1,pd[0]不用),0 表示未达站点,1 表示出发站,-1 表示终点站。

// return:

{

#ifdef _DEBUG

dumpMap(n, ph, pl);

dumpDeep(n, pd);

#endif //_DEBUG

assert(n > 2);

int i; //循环计数器

Q_NODE *Qs,  //队列头部

*Qe, //队列尾部

*pQ1, //队列元素指示器

*pQ2;

Qs = Qe = queue_alloc(_BUF_SIZE_);

//出发节点加入队列

for (i = 1; i < n + 1; i++)

{

if (1 == pd[i])

{

if (NULL == Qe->father)

{

Qe->id = 0;

Qe->father = queue_alloc(_BUF_SIZE_); //扩充队列

Qe = Qe->father; //跳过缓冲区末尾的节点

/*

缓冲区末尾的节点id为0(一个不可能出现的节点编码),

表示本节点的father指针指向下一个缓冲区的起始地址,

而不是本节点的父节点地址。

*/

}

pQ2 = Qe->father;

Qe->id = i;

Qe->father = (Q_NODE *)-1; //一个不可能出现的内存空间地址,但不可用NULL

Qe = pQ2;

}

}

#ifdef _DEBUG

dumpQueue(Qs);

dumpDeep(n, pd);

#endif //_DEBUG

//路径搜索

int w, //父节点的id

u; //子节点的id

pQ1 = Qs;

// 利用队列进行层级遍历

while (Qe != pQ1)

{

if ( 0 == pQ1->id )

pQ1 = pQ1->father;

w = pQ1->id;

// 遍历w的子节点

for (i = ph[w-1]; i < ph[w]; i++)

{

u = pl[i];

if (-1 == pd[u]) // 找到换乘通路

{

// ... 输出换乘通路

printf("(%d)", pd[w]);

printf("%d", u);

Q_NODE *path = pQ1;

while ((Q_NODE *)-1 != path)

{

printf(" - %d", path->id);

path = path->father;

}

printf("\n");

}

else if (0 == pd[u]     //未到达节点

|| pd[w] + 1 == pd[u] )  //已达,但属同一层

{

if (NULL == Qe->father) //扩充队列

{

Qe->id = 0;

Qe->father = queue_alloc(_BUF_SIZE_);

Qe = Qe->father; //跳过缓冲区末尾的节点

}

//添加节点

pQ2 = Qe->father;

Qe->id = u;

Qe->father = pQ1;

Qe = pQ2;

//标记换乘深度

pd[u] = pd[w] + 1;

}

}

#ifdef _DEBUG

dumpQueue(Qs);

dumpDeep(n, pd);

#endif //_DEBUG

//步进到下一节点

pQ1++;

}

//释放队列

queue_free(Qs, _BUF_SIZE_);

}

int main(int argc, char* argv[])

{

// 打开输入文件

FILE *in;

if (argc < 2)

in = fopen("Input.txt", "r");

else

in = fopen(argv[1], "r");

if (NULL == in)

{

fprintf(stderr, "Cannot open input file.\n");

return 1;

}

// 读取输入文件到邻接压缩表中

int num_node;

vector h; //邻接压缩表描述序列

vector l; //邻接压缩表序列,即可直达站点列表

vector mark; //节点到达标记序列

if (fscanf(in, "%d\n", &num_node))

{

assert(num_node>2);

h.resize(num_node+1);

h[0] = 0;

for (int i=0; i

{

int num_arrival;

fscanf(in, "%d", &num_arrival);

assert(num_arrival>0);

h[i+1] = num_arrival + h[i];

l.resize(h[i+1]);

for (int j=h[i]; j

{

int id_node;

fscanf(in, "%d", &id_node);

l[j] = id_node-1;

}

}

}

// 关闭输入文件

fclose(in);

// 调用函数搜索可行路径

{

int n = h.size() - 1;

int *ph = new int[h.size()];

int *pl = new int[l.size()];

copy(h.begin(), h.end(), ph);

copy(l.begin(), l.end(), pl);

for (int i=0; i

pl[i] = pl[i] + 1;

//  search_change(n, ph, pl, 1, 10);

//  search_change(n, ph, pl, 5, 10);

printf("\n");

int *pd = new int[h.size()];

memset(pd, 0, h.size() * 4);

pd[1] = 1;

pd[5] = 1;

pd[10] = -1;

search_change(n, ph, pl, pd);

delete[] pd;

delete[] ph;

delete[] pl;

}

// 搜索可行路径

int n_start = 0; //出发节点

int n_end = 11;  //目的节点

// 打开输出文件

FILE *out;

out = fopen("./Output.txt", "w+");

// 算法

{

mark.resize(h.size()-1);

{for (int i=0; i

vector< pair > Q; //队列,存储路径搜索树,记录节点序号和父节点在本队列中的位置

mark[n_start] = 0;

Q.push_back(make_pair(n_start,-1));

for (int i=0; i

{

int w = Q[i].first;

// 遍历w的直达节点

for (int j=h[w]; j

{

int u = l[j];

if (u == n_end) { //存在换乘通路

// 输出换乘通路

//利用w的父节点在队列中的位置进行上溯,找到换乘路径

fprintf(out, "%d: %d,%d,%d,%d,%d\n",

mark[w] + 1, u,w,Q[Q[i].second].first);

//Q[Q[Q[i].second].second].first,Q[Q[Q[Q[i].second].second].second].first);

}

else if (mark[u] == -1) { //未到达节点

Q.push_back(make_pair(u,i)); //子节点入栈并记录其父节点在队列中的位置

mark[u] = mark[w] + 1; //记录当前换乘深度

}

else if (mark[u] == mark[w] + 1) {

Q.push_back(make_pair(u,i));

}

}

}

}

// 测试输入部分的正确性

#ifdef _DEBUG

{

assert( out != NULL );

fprintf(out, "%d\n", h.size()-1);

for (int i=0; i

{

fprintf(out, "(%d) ", i + 1);

for (int j=h[i]; j

fprintf(out, "%d ", l[j] + 1);

fprintf(out, "\n");

}

}

#endif

// 关闭输出文件

fclose(out);

return 0;

}

} // extern "C"

《Input.txt》

12

4 3 4 2 5

2 8 1

2 9 7

2 6 11

3 8 2 3

2 9 10

2 10 11

1 12

2 10 12

1 12

1 12

2 5 8

《output.txt》

3: 11,8,2,0,0

3: 11,10,3,0,0

3: 11,7,1,0,0

3: 11,7,4,0,0

4: 11,9,8,0,0

4: 11,9,6,0,0

4: 11,9,5,0,0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/485548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记使用talend从oracle抽取数据时,数字变为0的问题

数据源为oracle&#xff0c;字段类型为number。 发现通过mainline连接到一个logrow控件&#xff0c;输入的该字段的值为0 经过多次测试还是没发现有什么规律。 通过查看代码发现有这一句内容。 if (row2.ID ! null) { //strBuffer_tLogRow_1.append(row2.ID.setScale(-127,java…

Leetcode--494. 目标和

给定一个非负整数数组&#xff0c;a1, a2, ..., an, 和一个目标数&#xff0c;S。现在你有两个符号 和 -。对于数组中的任意一个整数&#xff0c;你都可以从 或 -中选择一个符号添加在前面。 返回可以使最终数组和为目标数 S 的所有添加符号的方法数。 示例 1: 输入: nums…

C语言int r(int m),INT(M)表示什么意思?

根据官方文档描述&#xff0c;int(M)中的M表示数据显示的宽度&#xff0c;与实际存储的长度无关。1、也就是int(3)和int(11)能够存储的数据是一样的&#xff0c;都是从-2147483648到2147483647(或者0-4294967295)。2、int(M)只有联合zerofill参数才能有意义&#xff0c;否则int…

2021年值得关注的人工智能与机器学习的五大趋势

文章来源&#xff1a;科技心时代人工进行智能和机器可以学习是市场上的热门专业技术&#xff0c;其重要性在2020年达到顶峰&#xff0c;这两种信息技术发展已经到了广泛应用在各行业领域&#xff0c;其范围从电子商务到量子计算管理系统&#xff0c;从医疗诊断分析系统到消费电…

关于java子类继承以及final问题总结

(1)子类和父类如果在同一个包内&#xff0c;则子类可以继承父类的除private以外的所有成员变量和方法&#xff0c;并且权限不变&#xff1b; (2)子类和父类如果不在同一个包内&#xff0c;则子类可以继承父类的public和protected权限的成员变量和方法&#xff0c;不能继承友好型…

物理层基本概念

物理层解决如何在连接各种计算机的传输媒体上传输数据比特流 物理层定义了一些传输媒体接口的标准 定义了哪些标准&#xff1f; 1.机械特性 定义物理连接的特性&#xff0c;例如接口形状&#xff0c;引线数目&#xff0c;引脚数量等 2.电气特性 规定传输二进制位时&#…

qt android 应用程序图标大小,vs+qt 设置应用程序图标

LaTeX 学习记录4&#xff0d;字体设置LaTeX 学习记录4&#xff0d;字体设置 % 导言区\documentclass[10pt]{ctexart}%10pt为字体大小%使用ctexart后就可以不引用ctex宏包了\title{\heiti My LaTeX Document}%字体为黑体\author{\kaishu forever}%字体为楷书\date{\today}% 正文…

城市生态的机器人革命

来源&#xff1a; 脑极体城市居民能看到绿色、与自然亲近的机会&#xff0c;被高楼大厦挤压得越来越少&#xff0c;如果有一天&#xff0c;连机器人、无人车和无人机都要来侵占人类的休闲空间&#xff0c;会发生什么呢&#xff1f;至少目前看来&#xff0c;如果不采取措施&…

spring boot 三种入参

先来讲述下最简单的使用get请求用户信息的实现方式&#xff0c;代码如下,写好后直接在Application类点击右键有个RunAs&#xff0c;点击后会自动运行&#xff0c;运行成功后可以使用http发包工具进行测试&#xff0c;这里推荐使用chrome的postman或者使用firefox的httprequeste…

数据通信基础知识

常用的两种入网方式&#xff1a; 1. 电话线入网 电话线发出来的是数字信号&#xff0c;需要用调制解调器(&#x1f431;)转换位模拟信号 例如&#xff1a;我计算机发 在吗 &#xff0c;电话线发出来是01011100&#xff0c; 调制解调器把数字信号转为模拟信号发到广域网 之…

android okhttpclient设置编码,Android之okhttp实现socket通讯(非原创)

文章大纲一、okhttp基础介绍二、socket通讯代码实战三、项目源码下载四、参考文章一、okhttp基础介绍二、socket通讯代码实战1. 添加依赖和权限app的build.gradle下添加okhttp依赖implementation com.squareup.okhttp3:okhttp:3.8.1AndroidManifest.xml文件添加网络权限2. 添加…

张小龙两小时演讲全文:微信十年的产品思考

来源&#xff1a;微信公开课&#xff08;ID&#xff1a;wx-gongkaike&#xff09;文&#xff1a;张小龙大家好&#xff01;谢谢来到公开课现场的朋友们&#xff0c;让我感受到这是一个面对面的交流&#xff0c;而不是一个人面对屏幕的直播。2020&#xff0c;对很多人来说都是很…

Leetcode--113. 路径总和Ⅱ

给定一个二叉树和一个目标和&#xff0c;找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树&#xff0c;以及目标和 sum 22&#xff0c; 5 / \ 4 8 / / \ …

android url格式化,Android利用SpannableString实现格式化微博内容

前言在Android开发中&#xff0c;有许多信息展示需要通过TextView来展现&#xff0c;如果只是普通的信息展现&#xff0c;使用TextView setText(CharSequence str)设置即可&#xff0c;但是当在TextView里的这段内容需要截取某一部分字段&#xff0c;可以被点击以及响应响应的操…

[Unity]限制两个物体之间的距离

//限制两个物体之间的距离 if (Vector3.Distance(B.position, A.position) > maxDistance) {//获得两个物体之间的单位向量Vector3 pos (B.position - A.position).normalized;//单位向量乘以最远的距离系数pos * maxDistance;//物体A的坐标加上距离向量B.position pos A…

Leetcode--226. 翻转二叉树

翻转一棵二叉树。 示例&#xff1a; 输入&#xff1a; 4 / \ 2 7 / \ / \ 1 3 6 9 输出&#xff1a; 4 / \ 7 2 / \ / \ 9 6 3 1 提交的代码&#xff1a; /** * Definition for a binary tree node. * public class TreeNode { *…

2021年中国AIoT产业全景图谱

来源&#xff1a;物联网智库&#xff08;iot101&#xff09;编辑&#xff1a;蒲蒲日前&#xff0c;在“2020 AIoT产业年终盛典”上&#xff0c;物联网智库正式发布全新升级版的《2021中国AIoT产业全景图谱报告》&#xff08;以下简称“报告”&#xff09;。据悉&#xff0c;这是…

Leetcode--309. 最佳买卖股票时机含冷冻期

给定一个整数数组&#xff0c;其中第 i 个元素代表了第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 你不能同时参与多笔交易&#xff08;你必须在再次购买前…

2018.8.2 Juint测试介绍及其命名的规范

JUnit - 测试框架 什么是 Junit 测试框架&#xff1f; JUnit 是一个回归测试框架&#xff0c;被开发者用于实施对应用程序的单元测试&#xff0c;加快程序编制速度&#xff0c;同时提高编码的质量。JUnit 测试框架能够轻松完成以下任意两种结合&#xff1a;Eclipse 集成开发环境…

Leetcode--448. 找到所有数组中消失的数字

给定一个范围在 1 ≤ a[i] ≤ n ( n 数组大小 ) 的 整型数组&#xff0c;数组中的元素一些出现了两次&#xff0c;另一些只出现一次。 找到所有在 [1, n] 范围之间没有出现在数组中的数字。 您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回…