一、前言
欢迎大家来到这里~~
1、这次数据结构课设,笔者的题目是网页形式的导航系统。
2、数据结构方面应用了链表存储商品信息、图来存储景点和路径信息、在图的广度优先中还用到了队列;
3、具体的算法有图的广度优先、深度优先和迪杰斯特拉算法。
4、由于代码量较大,这里只做统一展示,每部分的详细说明会后续链接在下面。
二、详细链接
1、css部分的语句介绍。
2、使用说明链接。
3、景区导航可执行文件链接。
说明:笔者上传文件后系统判定需要一定的积分才能下载。本着开放共享的原则,如果有需要的读者可以联系我免费私发,有任何疑问也可以联系我,大家一起探讨。
三、编程语言以及环境说明
网页:HTML架构,JavaScript实现函数功能、css进行渲染。
环境配置:windows+火狐浏览器+VS2017+必要的扩展模块:ASP.Net和web开发、Node.js开发、.NET Core跨平台开发,这是笔者电脑上有关的扩展模块。(理论上网页编辑器都可以运行)
四、源代码
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>景点导游页</title>
<link rel="shortcut icon" href="/static/favicon.ico?v=8e930b3cedb17c7fd38fad027c852f3b">
<link href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet">
<link href="//cdn.bootcss.com/metisMenu/2.2.0/metisMenu.min.css" rel="stylesheet">
<link href="/static/css/sb-admin-2.css?v=830e19caba3dbcac4557872c4d5c83d4" rel="stylesheet">
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style type="text/css">
div.col-lg-3{
position:absolute;
top:-3px;
left:750px;
width:395px;
}
div.col-xs-3{
position:absolute;
top:-3px;
left:1115px;
width:405px;
}
div.col-md-6{
position:absolute;
top:142px;
left:750px;
width:770px;
}
div.col-sm-3{
position:absolute;
top:259px;
left:750px;
width:395px;
height:260px;
}
div.col-md-3{
position:absolute;
top:259px;
left:1115px;
width:405px;
}
div.col-md-12{
position:absolute;
top:500px;
margin-bottom: 41px;
}
ul.苏堤春晓{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:340px;
top:240px;
height:40px;
width:110px;
}
ul.平湖秋月{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:460px;
top:100px;
height:40px;
width:110px;
}
ul.断桥残雪{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:495px;
top:50px;
height:40px;
width:110px;
}
ul.曲院风荷{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:280px;
top:140px;
height:40px;
width:110px;
}
ul.雷锋夕照{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:485px;
top:365px;
height:40px;
width:110px;
}
ul.南屏晚钟{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:475px;
top:407px;
height:40px;
width:110px;
}
ul.花港观鱼{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:185px;
top:375px;
height:40px;
width:110px;
}
ul.柳浪闻莺{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:583px;
top:280px;
height:40px;
width:110px;
}
ul.双峰插云{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:138px;
top:175px;
height:40px;
width:110px;
}
ul.三潭印月{
align-content:center;
font-size:15px;
background:black;
position: absolute;
left:285px;
top:290px;
height:40px;
width:110px;
}
img.西湖{
height:500px;
width:750px;
}
li.drop_down1{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.苏堤春晓:hover li.drop_down1{
display:block;
}
li.drop_down2{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.平湖秋月:hover li.drop_down2{
display:block;
}
li.drop_down3{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.断桥残雪:hover li.drop_down3{
display:block;
}
li.drop_down4{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.曲院风荷:hover li.drop_down4{
display:block;
}
li.drop_down5{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.雷锋夕照:hover li.drop_down5{
display:block;
}
li.drop_down6{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.南屏晚钟:hover li.drop_down6{
display:block;
}
li.drop_down7{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.花港观鱼:hover li.drop_down7{
display:block;
}
li.drop_down8{
position:absolute;
top:40px;
left:-80px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.柳浪闻莺:hover li.drop_down8{
display:block;
}
li.drop_down9{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.双峰插云:hover li.drop_down9{
display:block;
}
li.drop_down10{
position:absolute;
top:40px;
vertical-align:text-top;
width:250px;
background:black;
color:cornflowerblue;
display:none;
z-index:1;
}
ul.三潭印月:hover li.drop_down10{
display:block;
}
canvas.画布 {
visibility:hidden;
position:absolute;
top:0;
left:0;
z-index:2;
}
a{/*设置成小手形状*/
cursor:pointer;
}
th{
font-weight: normal;
}
</style>
</head>
<body style="line-height:19px; background:url(https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2743733208,3597660481&fm=26&gp=0.jpg)" >
<!图片以及景点模块>
<div class="col-lg-12">
<img class="西湖" src="http://www.cncjj.com/uploads/allimg/160421/2353122335-0.jpg" alt="西湖背景" />
<ul class="苏堤春晓" id="苏堤春晓">
<a onclick="click1()">苏堤春晓</a>
<li class="drop_down1">
<a href="https://gss1.bdstatic.com/-vo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=dcbe42d766061d95694b3f6a1a9d61b4/e4dde71190ef76c6d250c0c49516fdfaae51675a.jpg">苏堤自北宋始建至今,一直保持了沿堤两侧相间种植桃树和垂柳的植物景观特色。
春季拂晓是欣赏“苏堤春晓”的最佳时间,此时薄雾蒙蒙,垂柳初绿、桃花盛开,尽显西湖旖旎的柔美气质
。</a>
</li>
</ul>
<ul class="平湖秋月" id="平湖秋月">
<a onclick="click2()">平湖秋月</a>
<li class="drop_down2">
<a href="https://gss3.bdstatic.com/7Po3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=6abe05a40a087bf469e15fbb93ba3c49/77c6a7efce1b9d168ad1a08efbdeb48f8d5464ce.jpg">位于孤山东南角的滨湖地带、白堤西端南侧,是自湖北岸临湖观赏西湖水域全景的最佳地点之一。
以秋天夜晚皓月当空之际观赏湖光月色为主题。</a>
</li>
</ul>
<ul class="断桥残雪" id="断桥残雪">
<a onclick="click3()">断桥残雪</a>
<li class="drop_down3">
<a href="https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=d4a1c02316178a82da3177f2976a18e8/902397dda144ad340f05bd68d8a20cf430ad85a2.jpg">位于在西湖北部白堤东端的断桥一带, 范围约2.61公顷。尤以冬天观赏西湖雪景为胜。
当西湖雪后初晴时,日出映照,断桥向阳的半边桥面上积雪融化、露出褐色的桥面一痕,仿佛长长的白链到此中断了, 呈“雪残桥断”之景。
</a>
</li>
</ul>
<ul class="曲院风荷" id="曲院风荷">
<a onclick="click4()">曲院风荷</a>
<li class="drop_down4">
<a href="https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2225150aa56eddc432eabca958b2dd98/730e0cf3d7ca7bcb2697fcc0b6096b63f724a874.jpg">位于西湖北岸的苏堤北端西侧22米处,范围约0.06公顷,以夏日观荷为主题,
在视觉上呈现出“接天莲叶无穷碧,映日荷花别样红”的特色。
</a>
</li>
</ul>
<ul class="雷锋夕照" id="雷锋夕照">
<a onclick="click5()">雷锋夕照</a>
<li class="drop_down5">
<a href="https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=24ed1925593d26973ade000f3492d99e/bd315c6034a85edf09b0dacc41540923dd547524.jpg">雷峰塔还因中国四大民间爱情故事之一的《白蛇传》而成为爱情坚贞的象征,
赋予了西湖景观丰富的历史内涵。</a>
</li>
</ul>
<ul class="南屏晚钟" id="南屏晚钟">
<a onclick="click6()">南屏晚钟</a>
<li class="drop_down6">
<a href="https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=41f96a140246f21fdd395601974d0005/18d8bc3eb13533fa14b8b7c1a0d3fd1f40345bd6.jpg">每当佛寺晚钟敲响,钟声振荡频率传到山上的岩石、洞穴,
随之形成悠扬共振齐鸣的钟声。</a>
</li>
</ul>
<ul class="花港观鱼" id="花港观鱼">
<a onclick="click7()">花港观鱼</a>
<li class="drop_down7">
<a href="https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=d491c02316178a82da3177f2976a18e8/902397dda144ad340f35bd68d8a20cf430ad8552.jpg">“花港观鱼”位于南宋时(12-13世纪)官员卢允升的别墅内,
因所在位置水域名花港,别墅内凿池养鱼,故名“花港观鱼”。
该景观单元现存御碑、御碑亭、鱼池及假山等遗址。</a>
</li>
</ul>
<ul class="柳浪闻莺" id="柳浪闻莺">
<a onclick="click8()">柳浪闻莺</a>
<li class="drop_down8">
<a href="https://gss3.bdstatic.com/-Po3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=7422d9e278cf3bc7fc0dc5beb069d1c4/10dfa9ec8a13632771fbe7dc998fa0ec09fac7ce.jpg">“柳浪闻莺”所处的位置原为南宋时(12-13世纪)的御花园——“聚景园”,
因园中多柳树,风摆成浪、莺啼婉转,故得题名“柳浪闻莺”。
如今,“柳浪闻莺”依然保留了传统的柳林特色,漫步其间,且行且听,柳丝拂面,莺鸟鸣啼,
一派生机盎然的景象。</a>
</li>
</ul>
<ul class="双峰插云" id="双峰插云">
<a onclick="click9()">双峰插云</a>
<li class="drop_down9">
<a href="https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f2fdc4e08f94a4c21e2eef796f9d70b0/4e4a20a4462309f7b42788fd7a0e0cf3d6cad690.jpg">西湖南北高峰在唐宋时各有塔一座,在春、秋晴朗之日远望两峰,
可见遥相对峙的双塔巍然耸立,气势非凡。每当云雾弥漫,塔尖于云中时隐时显,若云天佛国。
</a>
</li>
</ul>
<ul class="三潭印月" id="三潭印月">
<a onclick="click10()">三潭印月</a>
<li class="drop_down10">
<a href="https://gss1.bdstatic.com/-vo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=ae6e44383ed12f2eda08a6322eabbe07/c995d143ad4bd113a67292dd52afa40f4afb05a5.jpg">在西湖外湖西南部的小瀛洲岛及岛南局部水域,
范围约7.67公顷,是杭州西湖最具标志性的景观。该景观以水中三塔、小瀛洲岛为核心观赏要素,
以月夜里在岛上观赏月、塔、湖的相互映照、引发禅境思考和感悟为欣赏主题。</a>
</li>
</ul>
</div>
<canvas class="画布" id="myCanvas" width=750 height=500></canvas>
<!查询商品模块>
<div class="col-lg-3">
<div class="panel panel-primary">
<div class="panel-heading"> <i class="fa fa-search fa-fw"></i>
输入商品名
</div>
<div class="panel-body">
<form>
<div class="form-group">
<input type="text" class="form-control" id="goods_name"
placeholder="请输入,如矿泉水"></div>
<button type="button" onclick="get_infomation()">查询详情</button>
</form>
</div>
</div>
</div>
<!插入商品信息>
<div class="col-xs-3">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-pencil-square-o fa-fw"></i>
插入信息窗口
</div>
<div class="panel-body">
<form>
<div class="form-group">
<input type="text" class="form-control" id="insert_infomation"
placeholder="请输入,如'卫龙,2,2019-03-25,安徽'">
</div>
<button type="button" onclick="insert()">插入数据</button>
<button type="button" onclick="delete_element()">删除数据</button>
</form>
</div>
</div>
</div>
<!查询商品结果>
<div class="col-md-6" id="select_answers">
<div class="panel panel-primary">
<div class="panel-heading">
小卖部查询结果<i class="fa fa-bar-chart fa-fw"></i>
</div>
<table class="table table-hover table-bordered" >
<tr>
<th >商品名称</th>
<th >价格</th>
<th class="as">保质期至</th>
<th class="as">产地</th>
</tr>
<tbody id="table_select">
<tr>
<th >矿泉水</th>
<th >2</th>
<th >2019-09-30</th>
<th >威海</th>
</tr>
</tbody>
</table>
</div>
</div>
<!查询路径>
<div class="col-sm-3">
<div class="panel panel-primary">
<div class="panel-heading"> <i class="fa fa-search fa-fw"></i>
输入起止位置查询路径
</div>
<div class="panel-body">
<input type="text" class="form-control" id="start_postion"
placeholder="请输入起点,如苏堤春晓">
<br />
<input type="text" class="form-control" id="end_postion"
placeholder="请输入终点,如三潭印月">
<br/>
<button type="button" onclick="draw()">显隐直线路径</button>
<br/><br/>
<button type="button" onclick="Dijkstra()">输出路径</button>
<button type="button" onclick="help()">帮助</button>
</div>
</div>
</div>
<!中断路径点>
<div class="col-md-3">
<div class="panel panel-primary">
<div class="panel-heading"> <i class="fa fa-search fa-fw"></i>
输入拥挤景点编号
</div>
<div class="panel-body">
<input type="text" class="form-control" id="choose_path" placeholder="这里将显示您需要的路径" />
<br/>
<input id="busy_scenery" class="form-control" placeholder="请输入要添加/解禁景点的编号">
<br/>
<button type="button" onclick="insert_busy_point()">(添加/解禁)繁忙景点</button>
<br/><br/>
<input id="busy_scenery_now" class="form-control" placeholder="这里将显示当前繁忙景点编号">
</div>
</div>
</div>
<!商品列表>
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
常见商品价格公示(由区域内所有商店制定、遵守)<i class="fa fa-bar-chart fa-fw"></i>
</div>
<table class="table table-hover table-bordered">
<caption class="text-center" onclick="initial_insert()">商品记录详细信息(点击添加原有商品)</caption>
<tr>
<th id="th0" onclick="SortTable(this)" class="as">商品名称<i class="fa fa-sort-alpha-asc" ></i></th>
<th id="th1" onclick="SortTable(this)" class="as">价格<i class="fa fa-sort-alpha-asc" ></i></th>
<th id="th2" onclick="SortTable(this)" class="as">保质期至<i class="fa fa-sort-alpha-asc" ></i></th>
<th id="th3" onclick="SortTable(this)" class="as">产地<i class="fa fa-sort-alpha-asc" ></i></th>
</tr>
<tbody id="table_goods">
</tbody>
</table>
</div>
</div>
</body>
</html>
<!排序函数>
<script type="text/javascript">
//得到其中的数字
function getNum(text) {
var value = text.replace(/[^0-9]/ig, "");
return value;
}
function sortnumber(s1, s2) {
num1 = getNum(s1);
num2 = getNum(s2);
//如果是纯字符串,即其中没有数字
if (num1 == "" && num2 == "") {
if (s1.length < s2.length) {
return -1;
}
else if (s1.length > s2.length) {
return 0;
}
else {
return 1;
}
}
//否则,如果有数字
else
return num1 - num2;
}
function SortTable(obj){
var td0s=document.getElementsByName("td0");//得到id为td0的一串列表,下相同
var td1s=document.getElementsByName("td1");
var td2s=document.getElementsByName("td2");
var td3s=document.getElementsByName("td3");
var tdArray0=[];
var tdArray1=[];
var tdArray2=[];
var tdArray3=[];
for(var i=0;i<td0s.length;i++){
tdArray0.push(td0s[i].innerHTML);
}//每串都写到数组中
for(var i=0;i<td1s.length;i++){
tdArray1.push(td1s[i].innerHTML);
}
for(var i=0;i<td2s.length;i++){
tdArray2.push(td2s[i].innerHTML);
}
for(var i=0;i<td3s.length;i++){
tdArray3.push(td3s[i].innerHTML);
}
var tds = document.getElementsByName("td" + obj.id.substr(2, 1));
//得到当前传入对象的那一列
var columnArray=[];
for(var i=0;i<tds.length;i++){
columnArray.push(tds[i].innerHTML);
}//当前那一列都写入column这个栈,是逆序的
var orginArray=[];
for(var i=0;i<columnArray.length;i++){
orginArray.push(columnArray[i]);
}//将这一列的内容再存储一遍,一会原来列表修改以后,
//通过比对值的方式对应到当前行的内容,实现同行内容一起修改
columnArray.sort(sortnumber); //排序后的新值,只排序了当前列
for(var i=0;i<columnArray.length;i++){//排序后列长,根据这个顺序添加每行
for(var j=0;j<orginArray.length;j++){//列长
if(orginArray[j]==columnArray[i]){//在循环中,开始每个i赋值一个j
document.getElementsByName("td0")[i].innerHTML=tdArray0[j];
document.getElementsByName("td1")[i].innerHTML=tdArray1[j];
document.getElementsByName("td2")[i].innerHTML=tdArray2[j];
document.getElementsByName("td3")[i].innerHTML=tdArray3[j];
orginArray[j]=null;
break;
}
}
}
}
</script>
<!链表存储商品数据>
<script type="text/javascript">
//节点定义
function Node(element1, element2, element3, element4) {
this.商品名称 = element1;
this.价格 = element2;
this.保质期至 = element3;
this.产地 = element4;
this.next = null;
}
//定义一个头节点
var head = new Node("矿泉水", "2", "2019-09-30", "威海");
function find(item) {
var curr_node = initial();//头节点
while (curr_node != null && curr_node.商品名称 != item )
curr_node = curr_node.next;
if (curr_node == null) return 0;
else return curr_node;
}
var flag_f = 1;//只在第一次调用才往链表中传输数据
function initial() {
if (flag_f==1) {
var list_goods = [
["红牛", "6", "2020-08-15", "云南"],
["方便面", "5", "2023-09-01", "天津"],
["创可贴", "10", "2019-10-13", "福州"],
["餐巾纸", "1", "2022-12-06", "广州"],
["面包", "4", "2019-07-15", "杭州"]
];
for (let i = 0; i < list_goods.length; i++) {
item = list_goods[i];
var new_node = new Node(item[0], item[1], item[2], item[3]);
var current = head;
new_node.next = current.next;
current.next = new_node;
}
}
flag_f = 0;
return head;
}
flag_first = 1;//为了只往表格中添加一次数据
function initial_insert() {//这个功能是初始化输入
//插入链表,从头节点开始向下遍历
if (flag_first) {
$("#table_goods").empty();
var current = initial();
while (current != null) {
display(current.商品名称, current.价格, current.保质期至, current.产地);
current = current.next;
}
}
flag_first = 0;
}
//item是要插入元素前面的位置
function insert() {//这个功能是在网页上,用输入框插入的
var insert_s = document.getElementById("insert_infomation").value;
var list_new_node = insert_s.split(",");
if (list_new_node.length != 4)
alert("请按照格式输入~~");
else {
//插入链表
var new_node = new Node(list_new_node[0], list_new_node[1], list_new_node[2], list_new_node[3]);
var current = head;
new_node.next = current.next;
current.next = new_node;
flag_first = 1;
initial_insert();
}
}
function delete_element(){
var delete_s = document.getElementById("insert_infomation").value;
delete_node = delete_s.split(",");
if (delete_node.length != 4) alert("请按照格式输入~");
else {
var current = head;
if (current.商品名称 == delete_node[0] && current.价格 == delete_node[1]
&& current.保质期至 == delete_node[2] && current.产地 == delete_node[3]) {
current = head.next;
head = null;
head = current;
flag_first = 1;
initial_insert();
}
else {
current = head.next;
var curpre = head;
while (current!=null && !(current.商品名称 == delete_node[0] && current.价格 == delete_node[1]
&& current.保质期至 == delete_node[2] && current.产地 == delete_node[3])) {
current = current.next;
curpre = curpre.next;
}
if (current == null) alert("当前没有此商品~");
else {
curpre.next = current.next;
current = null;
flag_first = 1;
initial_insert();
}
}
}
}
function display(name,price,date,location) {
//显示到表格中
text = "";
text +="<tr>"
+ "<td name='td0'>" + name + "</td>"
+ "<td name='td1'>" + price + "</td>"
+ "<td name='td2'>" + date + "</td>"
+ "<td name='td3'>" + location + "</td>"
+ "</tr>";
$("#table_goods").append(text);
}
</script>
<!在链表中查找商品函数>
<script type="text/javascript">
function get_infomation() {
$("#table_select").empty();
var goods_name = document.getElementById("goods_name").value;
if (goods_name == "") {
alert("请输入商品名~~");
}
else if (find(goods_name)) {
var current_node = find(goods_name);
var s = "";
s += "<tr>"
+ "<td>" + current_node.商品名称 + "</td>"
+ "<td>" + current_node.价格 + "</td>"
+ "<td>" + current_node.保质期至 + "</td>"
+ "<td>" + current_node.产地 + "</td>"
+ "</tr>";
$("#table_select").append(s);
}
else {
alert("请输入小卖部有的商品名");
}
}
</script>
<!绘制线路图>
<script type="text/javascript">
function draw() {
//画板点击显隐
if(document.getElementById("myCanvas").style.visibility=="hidden")
document.getElementById("myCanvas").style.visibility = "visible";
else document.getElementById("myCanvas").style.visibility = "hidden";
var myCanvas = document.getElementById('myCanvas');
myCanvas.width = myCanvas.width;
var ctx = myCanvas.getContext('2d');
ctx.lineWidth = 2;
ctx.strokeStyle = 'rgba(255, 0, 0) ';
var num_s = Dijkstra();
if (num_s.length > 1) {
var nums = num_s.split("->");
for (let i = 0; i < nums.length; i++) {
nums[i] = parseInt(nums[i]);
}
var i = 0;
while (i + 1 <= nums.length) {
var num1 = parseInt(nums[i]) - 1;
var num2 = parseInt(nums[i + 1]) - 1;
if ((num1 == 0 && num2 == 1) || (num2 == 0 && num1 == 1)) {
ctx.moveTo(326, 257);
ctx.lineTo(295, 164);
ctx.lineTo(400, 162);
ctx.lineTo(443, 129);
}
else if ((num1 == 0 && num2 == 3) || (num2 == 0 && num1 == 3)) {
ctx.moveTo(262, 155);
ctx.lineTo(295, 157);
ctx.lineTo(325, 254);
}
else if ((num1 == 0 && num2 == 5) || (num2 == 0 && num1 == 5)) {
ctx.moveTo(325, 254);
ctx.lineTo(354, 350);
ctx.lineTo(402, 430);
ctx.lineTo(462, 419);
}
else if ((num1 == 0 && num2 == 6) || (num2 == 0 && num1 == 6)) {
ctx.moveTo(325, 254);
ctx.lineTo(341, 306);
ctx.lineTo(301, 304);
ctx.lineTo(270, 335);
ctx.lineTo(278, 390);
ctx.lineTo(310, 402);
}
else if ((num1 == 0 && num2 == 8) || (num2 == 0 && num1 == 8)) {
ctx.moveTo(325, 254);
ctx.lineTo(342, 304);
ctx.lineTo(301, 304);
ctx.lineTo(281, 282);
ctx.lineTo(258, 288);
ctx.lineTo(235, 194);
ctx.lineTo(121, 191);
}
else if ((num1 == 0 && num2 == 9) || (num2 == 0 && num1 == 9)) {
ctx.moveTo(325, 254);
ctx.lineTo(338, 309);
ctx.lineTo(415, 301);
}
else if ((num1 == 1 && num2 == 2) || (num2 == 1 && num1 == 2)) {
ctx.moveTo(441, 123);
ctx.lineTo(479, 75);
}
else if ((num1 == 1 && num2 == 3) || (num2 == 1 && num1 == 3)) {
ctx.moveTo(441, 123);
ctx.lineTo(391, 162);
ctx.lineTo(260, 157);
}
else if ((num1 == 2 && num2 == 7) || (num2 == 2 && num1 == 7)) {
ctx.moveTo(478, 75);
ctx.lineTo(522, 45);
ctx.lineTo(576, 76);
ctx.lineTo(628, 155);
ctx.lineTo(600, 186);
ctx.lineTo(602, 222);
ctx.lineTo(564, 275);
ctx.lineTo(567, 296);
}
else if ((num1 == 3 && num2 == 8) || (num2 == 3 && num1 == 8)) {
ctx.moveTo(261, 144);
ctx.lineTo(152, 126);
ctx.lineTo(133, 193);
}
else if ((num1 == 4 && num2 == 5) || (num2 == 4 && num1 == 5)) {
ctx.moveTo(470, 393);
ctx.lineTo(459, 422);
}
else if ((num1 == 4 && num2 == 7) || (num2 == 4 && num1 == 7)) {
ctx.moveTo(470, 393);
ctx.lineTo(541, 377);
ctx.lineTo(550, 348);
ctx.lineTo(570, 322);
ctx.lineTo(568, 302);
}
else if ((num1 == 5 && num2 == 6) || (num2 == 5 && num1 == 6)) {
ctx.moveTo(458, 421);
ctx.lineTo(399, 428);
ctx.lineTo(336, 454);
ctx.lineTo(302, 401);
}
else if ((num1 == 5 && num2 == 8) || (num2 == 5 && num1 == 8)) {
ctx.moveTo(461, 420);
ctx.lineTo(398, 426);
ctx.lineTo(350, 344);
ctx.lineTo(341, 315);
ctx.lineTo(318, 307);
ctx.lineTo(257, 289);
ctx.lineTo(235, 207);
ctx.lineTo(124, 191);
}
else if ((num1 == 5 && num2 == 9) || (num2 == 5 && num1 == 9)) {
ctx.moveTo(461, 420);
ctx.lineTo(398, 426);
ctx.lineTo(350, 344);
ctx.lineTo(340, 311);
ctx.lineTo(412, 306);
}
else if ((num1 == 6 && num2 == 8) || (num2 == 6 && num1 == 8)) {
ctx.moveTo(307, 399);
ctx.lineTo(234, 348);
ctx.lineTo(218, 324);
ctx.lineTo(257, 290);
ctx.lineTo(232, 208);
ctx.lineTo(121, 191);
}
else if ((num1 == 6 && num2 == 9) || (num2 == 6 && num1 == 9)) {
ctx.moveTo(310, 401);
ctx.lineTo(215, 332);
ctx.lineTo(257, 289);
ctx.lineTo(235, 207);
ctx.lineTo(123, 189);
}
else if ((num1 == 8 && num2 == 9) || (num2 == 8 && num1 == 9)) {
ctx.moveTo(123, 189);
ctx.lineTo(235, 207);
ctx.lineTo(257, 289);
ctx.lineTo(318, 307);
ctx.lineTo(416, 303);
}
ctx.stroke();
i = i + 1;
}
}
else {
alert("此时没有路径,无法绘制");
}
}
</script>
<!点击添加景点名到输入框>
<script>
function click1() { click_to_input("苏堤春晓"); }
function click2() { click_to_input("平湖秋月"); }
function click3() { click_to_input("断桥残雪"); }
function click4() { click_to_input("曲院风荷"); }
function click5() { click_to_input("雷锋夕照"); }
function click6() { click_to_input("南屏晚钟"); }
function click7() { click_to_input("花港观鱼"); }
function click8() { click_to_input("柳浪闻莺"); }
function click9() { click_to_input("双峰插云"); }
function click10() { click_to_input("三潭印月"); }
var a = 0;
function click_to_input(position_keywords) {
var start = document.getElementById("start_postion");
var end = document.getElementById("end_postion");
if (!start.value) {
start.value = position_keywords;
}
else if (!end.value) {
end.value = position_keywords;
}
else if (a == 0) {
start.value = position_keywords;
a = 1;
}
else if (a == 1) {
end.value = position_keywords;
a = 0;
}
else alert("您可以先清空一个框的内容,信息会自动添加到空白框");
}
function help() {
alert("在这个输入框中:\n\t1、第一个输入框内容为起点。\n\t2、第二个输入框内容为终点。\n\t3、路径显示状态下不能点击插入位置信息。\n");
}
</script>
<!图结构,返回一个调用函数返回一个二维列表>
<script type="text/javascript">
function Graph(v) {
this.vertices = v;//顶点数目
this.edges = 0;//边数目
this.adj = [];//每个边的相邻边
this.edge_len = new Array();
for (var i = 0; i < this.vertices; i++) {
this.adj[i] = [];
}
this.addEdge = addEdge;//添加边
this.showGraph = showGraph;//展示表格
//记录已经访问过的顶点
this.marked = [];
//初始化全部写成false
for (var i = 0; i < this.vertices; i++) {
this.marked[i] = false;
}
this.dfs = dfs;
this.bfs = bfs;
}
function addEdge(v, w, l) {//两个点的相邻边都有彼此,边的总数加一
//this.adj[v].push(w);
//this.adj[w].push(v);
//this.edges++;
var key = String(v) + "+" + String(w);
this.edge_len[key] = l;
}
function showGraph() {//一排排的输出不为空的元素
for (var i = 0; i < this.vertices; i++) {
for (var j = 0; j < this.vertices; j++) {
if (this.adj[i][j] != undefined) {
console.log(i + "->" + this.adj[i][j])
}
}
}
}
//深度优先搜索
function dfs(v) {
this.marked[v] = true;
//访问每个相邻边
if (this.adj[v] != undefined) {
console.log("已访问 :" + v);
console.log(this.marked, "adj")
}
//从v这个点开始,向下遍历,然后扩展到到所有的相邻边
for (var i = 0; i < this.adj[v].length; i++) {
var w = this.adj[v][i];
if (!this.marked[w]) {
console.log("123456")
this.dfs(w);
}
}
}
//广度优先
function bfs(s) {
//使用队列对每一行的进行遍历,然后再对下一层遍历
var queue = [];
this.marked[s] = true;
queue.push(s);
while (queue.length > 0) {
var v = queue.shift();
if (v != undefined) {
console.log("已访问 :" + v);
}
for (var k in this.adj[v]) {//k是v的相邻边
var w = this.adj[v][k];
if (!this.marked[w]) {
this.marked[w] = true;
queue.push(w);
}
}
}
}
function graph_to_store() {
var obj = new Graph(10);
obj.addEdge(1, 2, 11);
obj.addEdge(1, 4, 5);
obj.addEdge(1, 6, 13);
obj.addEdge(1, 7, 8);
obj.addEdge(1, 9, 10);
obj.addEdge(1, 10, 3);
obj.addEdge(2, 3, 2);
obj.addEdge(2, 4, 7);
obj.addEdge(3, 8, 17);
obj.addEdge(4, 9, 5);
obj.addEdge(5, 6, 3);
obj.addEdge(5, 8, 5);
obj.addEdge(6, 7, 6);
obj.addEdge(6, 9, 22);
obj.addEdge(6, 10, 13);
obj.addEdge(7, 9, 14);
obj.addEdge(7, 10, 9);
obj.addEdge(9, 10, 16);
//obj.showGraph();
//深度优先搜索
//obj.dfs(0);
//广度优先搜索
//obj.bfs(0);
return obj.edge_len;
}
function get_matrix() {
const m = Infinity;
const matrix = [
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m],
[m, m, m, m, m, m, m, m, m, m]
];
var graph = graph_to_store();
for (var key in graph) {
var value = graph[key];
var k1 = parseInt(key.split("+")[0]) - 1;
var k2 = parseInt(key.split("+")[1]) - 1;
matrix[k1][k2] = value;
matrix[k2][k1] = value;
}
return matrix;
}
</script>
<!dijkstra函数求最短路径>
<script type="text/javascript">
function contains(arr, obj) {
var i=arr.length;
//判断元素是否存在
while(i--){
if(arr[i]==obj){
return true;//若存在返回true
}
}
return false;//若不存在返回false
}
const m = Infinity;//没有边或者有向图中无法到达
var matrix_temp = get_matrix();//使用这个中间变量实现修改停用点的操作
var close_points = [];
function insert_busy_point() {
var close_point_s = document.getElementById("busy_scenery").value;
var close_point_temp = close_point_s.split(",");
for (let i = 0; i < close_point_temp.length; i++) {
var close_point = parseInt(close_point_temp[i]);
if (close_point > 0 && close_point < 11) {
//如果关闭点集中没有这个点,则封闭这个点
if (!(contains(close_points, close_point - 1))) {
close_points.push(close_point - 1);
}
else {//若这个元素已经存在于数组中,则解开这个元素
for (let i = 0; i < close_points.length; i++) {
if (close_points[i] == close_point - 1) {
close_points.splice(i, 1);
matrix_temp = get_matrix();
}
}
}
}
else if (close_point)
alert("请输入正确的编号");
}
var busy_scenery_now = document.getElementById("busy_scenery_now");
text = "";
for (let i = 0; i < close_points.length; i++) {
text += String(close_points[i]+1) + ",";
}
text = text.substring(0, text.length - 1);
busy_scenery_now.value = text;
}
function Dijkstra() {
//若封路列表不为空,先封路
if (close_points.length > 0) {
for (let t = 0; t < close_points.length; t++) {
var temp = close_points[t];
for (let i = 0; i < matrix_temp.length; i++) {
if (i == temp) {//如果是这一行,横向全部置为极大值
for (let j = 0; j < matrix_temp[i].length; j++) {
matrix_temp[i][j] = m;
}
}
else {//否则这一行只需要改变一个元素,最终纵向全部置为极大值
matrix_temp[i][temp] = m;
}
}
}
}
else matrix_temp = get_matrix();
var matrix = matrix_temp;
var list_postion = ["苏堤春晓", "平湖秋月", "断桥残雪",
"曲院风荷", "雷锋夕照", "南屏晚钟", "花港观鱼",
"柳浪闻莺","双峰插云","三潭印月"];
var s_start = document.getElementById("start_postion").value;
var s_end = document.getElementById("end_postion").value;
if (!(contains(list_postion,s_start) && contains(list_postion,s_end))) {
alert("请输入正确的地址");
}
else {
var index1 = list_postion.indexOf(s_start);
var index2 = list_postion.indexOf(s_end);
start = index1;
const rows = matrix.length,//rows和cols一样,其实就是顶点个数
cols = matrix[0].length;
if (rows !== cols || start >= rows)alert("邻接矩阵错误或者源点错误");
//初始化distance
const distance = new Array(rows).fill(m);
var distance_path = new Array();
distance[start] = 0;
var flag = 1;
var n = 12;
//核心循环
while (flag == 1 && n>0) {
n = n - 1;//防止网页卡死
for (let i = 0; i < rows; i++) {
//达到不了的顶点不能作为中转跳点
if (distance[i] < Infinity) {
for (let j = 0; j < cols; j++) {
//比如通过比较distance[i] + matrix[i][j]和distance[j]的大小来决定是否更新distance[j]。
if (matrix[i][j] + distance[i] < distance[j]) {
distance[j] = matrix[i][j] + distance[i];
if (distance_path[j] != undefined)
distance_path[j] += String(i + 1) +"->"+ String(j + 1) + "->";
else distance_path[j] = String(i + 1) +"->"+ String(j + 1) + "->";
}
}
}
}
flag = 0;
for (let i = 0; i < rows; i++) {
if (distance[i] == Infinity) flag = 1;
}
}
//第一个位置全部置为起点
var start_positon = String(index1 + 1);
for (let i = 0; i < rows; i++) {
var s = distance_path[i];
if (s != null) {
if (s.indexOf(start_positon) != 0) {
s = start_positon +"->"+ s;
}
}
else s = start_positon+"->";
distance_path[i] = s;
}
//删除前面多余选择的路径
for (let i = 0; i < rows; i++) {
var flag_end = 0;
var s1 = distance_path[i];
if (s1 != null) {
for (let j = 0; j < s1.length; j++) {
if (s1.charAt(j) == String(i+1) && j + 1 != 1) {
if (flag_end == 0) {
flag_end = j;
}
else {
s1 = s1.substring(flag_end+3, s1.length);
}
}
}
}
distance_path[i] = s1;
}
//第一个位置全部置为起点
for (let i1 = 0; i1 < rows; i1++) {
var s = distance_path[i1];
if (s != null) {
if (s.indexOf(start_positon) != 0 ) {
s = start_positon + "->" + s;
}
}
else s = start_positon + "->";
s = s.substring(0, s.length-2);
distance_path[i1] = s;
}
distance_path = complete(distance_path);
//输出到文本框
var choose_path = document.getElementById("choose_path");
if (distance[index2] != Infinity) {
choose_path.value = "路径:" + distance_path[index2]
+ ", 距离:" + distance[index2];
return distance_path[index2];
}
else {
choose_path.value = String(index1 + 1)+"<->"
+ String(index2 + 1) + "的所有路径已经被封闭";
return distance_path[index2];
}
}
}
//将路径由三个扩展到更长
function complete(distance_path) {
const matrix = get_matrix();
var num = [];
for (let i = 0; i < matrix.length; i++) {
num[i] = distance_path[i].split("->");
}
var flag_complete = 0;
while (flag_complete == 0) {
for (let i = 0; i < matrix.length; i++) {
var x = parseInt(num[i][0]);
var y = parseInt(num[i][1]);
if (matrix[x - 1][y - 1] == m) {//如果不能直接到达
num[i].splice(1, 0, num[y - 1][(num[y-1].length-2)]);
}
}
flag_complete = 1;
for (let i = 0; i < matrix.length; i++) {
var x = parseInt(num[i][0]);
var y = parseInt(num[i][1]);
if (matrix[x - 1][y - 1] == m) { flag_complete = 0; break; }
}
}
//将路径由abc表示成a->b->c的形式
for (let i = 0; i < matrix.length; i++) {
distance_path[i] = "";
for (let j = 0; j < num[i].length ; j++) {
distance_path[i] = distance_path[i] + "->" + num[i][j] ;
}
}
//删除前面的“->”
for (let i = 0; i < matrix.length; i++) {
distance_path[i] = distance_path[i].substring(2,distance_path[i].length);
}
return distance_path;
}
</script>