算法
196
JavaScript/教程/DOM对象.md
Normal file
@@ -0,0 +1,196 @@
|
||||
\>简介
|
||||
|
||||
\>\>document object
|
||||
model:文档对象模型,将HTML文档呈现为带有元素、属性和文本的树结构,成为节点树
|
||||
|
||||
\>\>三种DOM结点;
|
||||
|
||||
> 元素节点:\<html\>\<body\>\<p\>(tag)
|
||||
|
||||
> 文本节点:\<li\>\</li\>\<script\>\<css\>
|
||||
|
||||
> 属性节点:元素属性\<a href = "http://"\>其中href即为元素的属性
|
||||
|
||||

|
||||
|
||||
\>\>节点属性:
|
||||
|
||||
> nodeName:
|
||||
|
||||
> 1\. 元素节点的 nodeName 与标签名相同
|
||||
|
||||
> 2\. 属性节点的 nodeName 是属性的名称
|
||||
|
||||
> 3\. 文本节点的 nodeName 永远是\#text
|
||||
|
||||
> 4\. 文档节点的 nodeName 永远是\>\#document
|
||||
|
||||
> nodeType:节点类型1-\>元素节点;2-\>属性节点;3-\>文本节点
|
||||
|
||||
> nodeValue:节点值,元素节点返回null,属性节点返回属性值,文本节点返回文本内容
|
||||
|
||||
> 1\. 元素节点的 nodeValue 是 undefined 或 null
|
||||
|
||||
> 2\. 文本节点的 nodeValue 是文本自身
|
||||
|
||||
> 3\. 属性节点的 nodeValue 是属性的值
|
||||
|
||||
> childNodes:返回子节点数组(只有元素节点有子节点)
|
||||
|
||||
> firstChild:返回第一个子节点
|
||||
|
||||
> lastChild:返回最后一个子节点
|
||||
|
||||
> nextSibling:返回下一个兄弟节点
|
||||
|
||||
> previousSibling:返回节点的上一个兄弟节点
|
||||
|
||||
> parentNode:返回节点的父节点。
|
||||
|
||||
\>\>节点方法(是document对象的节点方法)
|
||||
|
||||
> write():写入内容到文档
|
||||
|
||||
> getElementBYId():返回指定ID的元素
|
||||
|
||||
> getElementsByTagName():返回带有制定标签名的所有元素(是一个数组)
|
||||
|
||||
> get/setAttribute('key', 'value'):返回设置属性节点
|
||||
|
||||
\>\>其他元素的结点方法:
|
||||
|
||||
| 节点方法 | 说明 |
|
||||
|----------------------------------|--------------------------------|
|
||||
| createElenment('tafName') | 创建元素节点 |
|
||||
| createTextNode(‘text’) | 创建文本节点 |
|
||||
| appendChild(o) | 在父节点末尾附加子节点 |
|
||||
| reateDocumentFragment() | 创建文档片段 |
|
||||
| removeChild(oP) | 删除节点 |
|
||||
| replaceChild(newOp,targetOp) | 替换节点 |
|
||||
| insertBefore(newOp,targerOp) | 已有的子节点前插入一个新的节点 |
|
||||
| insertAfter(newOp,targetOp) | 已有的子节点后插入一个新的节点 |
|
||||
| get/setAttribute('key', 'value') | 设置或得到属性节点 |
|
||||
| clonNode(true/false) | 复制节点 |
|
||||
|
||||
\>元素内容
|
||||
|
||||
> innerHTML(替换时包括其中的html标签)
|
||||
|
||||
> innerText(替换时只有其中的文本内容)
|
||||
|
||||
> 修改p标签的这两个值会得到不同的结果
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51898168)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51898168)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<p\>**JavaScript**\</p\>**
|
||||
|
||||
3. **\<p\>**JavaScript**\</p\>**
|
||||
|
||||
4. **\<input** type="button" id="inp" value="click"**\>**
|
||||
|
||||
5. **\<script** type="text/javascript"**\>**
|
||||
|
||||
6. var inp = document.getElementById('inp');
|
||||
|
||||
7. inp.onclick = function(){
|
||||
|
||||
8. var ip = document.getElementsByTagName('p');
|
||||
|
||||
9. alert(ip[0].innerHTML);
|
||||
|
||||
10. ip[0].innerHTML = "\<i\>hello\</i\>";
|
||||
|
||||
11. ip[1].innerText = "\<i\>hello\</i\>";
|
||||
|
||||
12. }
|
||||
|
||||
13. **\</script\>**
|
||||
|
||||
14. **\</body\>\</span\>**
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
\>元素样式
|
||||
|
||||
> 方法:
|
||||
|
||||
> style属性,能够创建新的属性并赋值
|
||||
|
||||
> className属性,只能改变标签的类属性,使用已经有的类来改变标签的属性
|
||||
|
||||
> 语法:
|
||||
|
||||
> object.style.property = new style;
|
||||
|
||||
> object.style.className = "class"
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51898168)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51898168)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<h2** id="ih"**\>**JavaScript**\</h2\>**
|
||||
|
||||
3. **\<input** type="button" id="inp" value="click"**\>**
|
||||
|
||||
4. **\<script** type="text/javascript"**\>**
|
||||
|
||||
5. var inp = document.getElementById("inp");
|
||||
|
||||
6. inp.onclick = function () {
|
||||
|
||||
7. var oh = document.getElementById("ih");
|
||||
|
||||
8. oh.style.color = "red";
|
||||
|
||||
9. oh.style.width = "300px";
|
||||
|
||||
10. oh.style.backgroundColor = "\#CCC";
|
||||
|
||||
11. }
|
||||
|
||||
12. **\</script\>**
|
||||
|
||||
13. **\</body\>\</span\>**
|
||||
|
||||
\>显示和隐藏
|
||||
|
||||
> display = none 或者block
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51898168)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51898168)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<p** id="ip"**\>**你可以把我隐藏,也可以让我显示哦\~**\</p\>**
|
||||
|
||||
3. **\<input** type="button" id="ihide" value="hide"**\>**
|
||||
|
||||
4. **\<input** type="button" id="ishow" value="show"**\>**
|
||||
|
||||
5. **\<script** type="text/javascript"**\>**
|
||||
|
||||
6. var op = document.getElementById("ip");
|
||||
|
||||
7. var inp = document.getElementsByTagName("input");
|
||||
|
||||
8. inp[0].onclick = function () {
|
||||
|
||||
9. op.style.display = "none";
|
||||
|
||||
10. }
|
||||
|
||||
11. inp[1].onclick = function () {
|
||||
|
||||
12. op.style.display = 'block';
|
||||
|
||||
13. }
|
||||
|
||||
14. **\</script\>**
|
||||
|
||||
15. **\</body\>\</span\>**
|
||||
99
JavaScript/教程/DOM对象三.md
Normal file
@@ -0,0 +1,99 @@
|
||||
\>页面尺寸
|
||||
|
||||
\>\>宽高尺寸
|
||||
|
||||
> clientWidth / clientHeight窗口的宽度高度
|
||||
|
||||
> scrollWidth / scrollHeight文档内容的高度宽度
|
||||
|
||||
> offsetWidth / offsetHeight文档内容的高度宽度
|
||||
|
||||
\>\>坐标位置
|
||||
|
||||
> scrollleft / scrollTop滚轴的水平便宜距离,垂直偏移距离
|
||||
|
||||
> offsetLeft / offsetTop对象与页面的边距
|
||||
|
||||
> event.clientX /
|
||||
> event.clientY事件触发时,鼠标指针对窗口的水平垂直坐标(event为时间)
|
||||
|
||||
//注意事项:documentElement是整个节点树的根节点root,即html标签,document.body也是document能直接调用的属性标签
|
||||
|
||||
语法:
|
||||
|
||||
> object.offsetLeft/oobject.offsetTop
|
||||
|
||||
\>拖拽功能的实现
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51900581)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51900581)
|
||||
|
||||
1. **\<html\>**
|
||||
|
||||
2. **\<head\>**
|
||||
|
||||
3. **\<meta** charset="UTF-8"**\>**
|
||||
|
||||
4. **\<title\>**event**\</title\>**
|
||||
|
||||
5. **\<style\>**
|
||||
|
||||
6. \#box {
|
||||
|
||||
7. width: 100px;
|
||||
|
||||
8. height: 100px;
|
||||
|
||||
9. background-color: aquamarine;
|
||||
|
||||
10. position: absolute;
|
||||
|
||||
11. }
|
||||
|
||||
12. **\</style\>**
|
||||
|
||||
13. **\</head\>**
|
||||
|
||||
14. **\<body\>**
|
||||
|
||||
15. **\<div** id="box"**\>\</div\>**
|
||||
|
||||
16. **\<script** type="text/javascript"**\>**
|
||||
|
||||
17. var oDiv = document.getElementById("box");
|
||||
|
||||
18. oDiv.onmousedown = function(ev){
|
||||
|
||||
19. var oEvent = ev;
|
||||
|
||||
20. var disX = oEvent.clientX-oDiv.offsetLeft;
|
||||
|
||||
21. var disY = oEvent.clientY-oDiv.offsetTop;
|
||||
|
||||
22. document.onmousemove = function(ev){
|
||||
|
||||
23. oEvent = ev;
|
||||
|
||||
24. oDiv.style.left = oEvent.clientX - disX +"px";
|
||||
|
||||
25. oDiv.style.top = oEvent.clientY - disY +"px";
|
||||
|
||||
26. }
|
||||
|
||||
27. document.onmouseup = function(){
|
||||
|
||||
28. document.onmousemove = null;
|
||||
|
||||
29. document.onmouseup = null;
|
||||
|
||||
30. }
|
||||
|
||||
31. }
|
||||
|
||||
32.
|
||||
|
||||
33. **\</script\>**
|
||||
|
||||
34. **\</body\>**
|
||||
|
||||
35. **\</html\>**
|
||||
306
JavaScript/教程/DOM对象二——节点与遍历.md
Normal file
@@ -0,0 +1,306 @@
|
||||
\>父子节点
|
||||
|
||||
\>\>childNode
|
||||
|
||||
> 使用语法:elementNode.childNodes
|
||||
|
||||
> 注意事项:空白节点会被浏览器但顾总文本节点
|
||||
|
||||
\>\>firstChild lastChild
|
||||
|
||||
> 使用语法:node.firstChild node.lastChild
|
||||
|
||||
\>\>parentNode
|
||||
|
||||
> 使用语法:elementNode.parentNode
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<ul** id="father"**\>**
|
||||
|
||||
3. **\<li\>**大娃**\</li\>**
|
||||
|
||||
4. **\</ul\>**
|
||||
|
||||
5. **\<script** type="text/javascript"**\>**
|
||||
|
||||
6. var li_num = 0;
|
||||
|
||||
7. var childNodes = document.getElementById("father").childNodes;
|
||||
|
||||
8. for(var i = 0; i **\<** **childNodes.length**; i++){
|
||||
|
||||
9. document.write("节点名:" + childNodes[i].nodeName + " ");
|
||||
|
||||
10. document.write("节点类型:" + childNodes[i].nodeType + " ");
|
||||
|
||||
11. if(childNodes[i].nodeType == 1){
|
||||
|
||||
12. document.write("我是" + childNodes[i].innerHTML + "**\<br\>**");
|
||||
|
||||
13. li_num++;
|
||||
|
||||
14. }
|
||||
|
||||
15. else{
|
||||
|
||||
16. document.write("**\<br\>**");
|
||||
|
||||
17. console.log("这是一个空节点,不用理他");
|
||||
|
||||
18. }
|
||||
|
||||
19. }
|
||||
|
||||
20. document.write("子节点数目:" + childNodes.length + "**\<br\>**");
|
||||
|
||||
21. document.write("li 子节点数目:" + li_num + "**\<br\>**");
|
||||
|
||||
22. document.write("文本子节点数目:" + (childNodes.length - li_num));
|
||||
|
||||
23. **\</script\>**
|
||||
|
||||
24. **\</body\>\</span\>**
|
||||
|
||||
//补充节点的属性还有title!
|
||||
|
||||
\>兄弟节点
|
||||
|
||||
> previousSibling nextSibling
|
||||
|
||||
> 使用语法:
|
||||
|
||||
> nodeobject.nextSibling / previousSibling
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<ul** id="father"**\>**
|
||||
|
||||
3. **\<li** title="force_max"**\>**大娃**\</li\>**
|
||||
|
||||
4. **\<li** id="second_children"**\>**二娃**\</li\>**
|
||||
|
||||
5. **\<li** title="fire"**\>**三娃**\</li\>**
|
||||
|
||||
6. **\</ul\>**
|
||||
|
||||
7. **\<script** type="text/javascript"**\>**
|
||||
|
||||
8. function getprenode(node){
|
||||
|
||||
9. var prenode = node.previousSibling;
|
||||
|
||||
10. while(prenode && prenode.nodeType != 1){
|
||||
|
||||
11. prenode = prenode.previousSibling;
|
||||
|
||||
12. }
|
||||
|
||||
13. return prenode;
|
||||
|
||||
14. }
|
||||
|
||||
15. function getnextnode(node){
|
||||
|
||||
16. var nextnode = node.nextSibling;
|
||||
|
||||
17. while(nextnode && nextnode.nodeType != 1){
|
||||
|
||||
18. nextnode =nextnode.nextSibling;
|
||||
|
||||
19. }
|
||||
|
||||
20. return nextnode;
|
||||
|
||||
21. }
|
||||
|
||||
22. var second_children = document.getElementById("second_children");
|
||||
|
||||
23. var first_children = getprenode(second_children);
|
||||
|
||||
24. var third_children = getnextnode(second_children);
|
||||
|
||||
25. alert(first\_children.innerHTML+first_children.title);
|
||||
|
||||
26. alert(third\_children.innerHTML+third_children.title);
|
||||
|
||||
27. **\</script\>**
|
||||
|
||||
28. **\</body\>\</span\>**
|
||||
|
||||
//虽然觉得这是史上最无聊的程序,但还是含泪贴上了
|
||||
|
||||
\>创建节点方法
|
||||
|
||||
> createElement('tagName'):创建节点
|
||||
|
||||
> crreateTextNode("text"):穿件文本节点
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>** var newinp =
|
||||
document.createElement("input");
|
||||
|
||||
2. alert(newinp);
|
||||
|
||||
3. var newtext = document.createTextNode("text");
|
||||
|
||||
4. alert(newtext);**\</span\>**
|
||||
|
||||
\>添加删除节点
|
||||
|
||||
> nodeobject.appendChild(newnode):父节点末尾添加
|
||||
|
||||
> nodeobject.removeChild(node):删除节点
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<ul** id="father"**\>**
|
||||
|
||||
3. **\<li\>**大娃**\</li\>**
|
||||
|
||||
4. **\</ul\>**
|
||||
|
||||
5. **\<input** type="button" id="createbtn" value="祭出紫金葫芦"**\>**
|
||||
|
||||
6. **\<script** type="text/javascript"**\>**
|
||||
|
||||
7. function createnode(){
|
||||
|
||||
8. var btn = document.createElement("input");
|
||||
|
||||
9. btn.setAttribute("type", "button");
|
||||
|
||||
10. btn.setAttribute("name", "紫金葫芦");
|
||||
|
||||
11. btn.setAttribute("value", "吸进去");
|
||||
|
||||
12. btn.setAttribute("onclick", "removenode()");
|
||||
|
||||
13. document.body.appendChild(btn);
|
||||
|
||||
14. }
|
||||
|
||||
15. function removenode(){
|
||||
|
||||
16. var fnode = document.getElementById("father");
|
||||
|
||||
17. var nodes = fnode.childNodes;
|
||||
|
||||
18. for(var i = 0; i **\<** **nodes.length**; i++){
|
||||
|
||||
19. if(nodes[i] && nodes[i].nodeType == 1){
|
||||
|
||||
20. var rm = fnode.removeChild(nodes[i]);
|
||||
|
||||
21. rm = null;
|
||||
|
||||
22. break;
|
||||
|
||||
23. }
|
||||
|
||||
24. }
|
||||
|
||||
25. }
|
||||
|
||||
26. var createbtn = document.getElementById("createbtn");
|
||||
|
||||
27. createbtn.onclick = createnode;
|
||||
|
||||
28. **\</script\>**
|
||||
|
||||
29. **\</body\>\</span\>**
|
||||
|
||||
//有很多需要注意的地方,等吃饭回来补充
|
||||
|
||||
> appendChild()方法的主体必须使父节点,而且只能添加到节点对类的末尾
|
||||
|
||||
\>插入节点
|
||||
|
||||
> fnode.insertBefore(newnode,node):可以指定插如节点的位置(在node之前)返回值是插入的节点
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<ul** id="father"**\>**
|
||||
|
||||
3. **\<li\>**二娃**\</li\>**
|
||||
|
||||
4. **\</ul\>**
|
||||
|
||||
5. **\<input** type="button" id="add-btn" value="add"**\>**
|
||||
|
||||
6. **\<script** type="text/javascript"**\>**
|
||||
|
||||
7. function addnode(){
|
||||
|
||||
8. var fnode = document.getElementById("father");
|
||||
|
||||
9. var newnode = document.createElement("li");
|
||||
|
||||
10. newnode.innerHTML = "大娃";
|
||||
|
||||
11. fnode.insertBefore(newnode, fnode.childNodes[0]);
|
||||
|
||||
12. }
|
||||
|
||||
13. var add = document.getElementById("add-btn");
|
||||
|
||||
14. add.onclick = addnode;
|
||||
|
||||
15. **\</script\>**
|
||||
|
||||
16. **\</body\>\</span\>**
|
||||
|
||||
\>替换子节点(克隆替换)
|
||||
|
||||
> fonde.replaceChild(newnode, oldnode) //返回值是被替换的节点
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51899305)
|
||||
|
||||
1. **\<span** style="font-size:14px;"**\>\<body\>**
|
||||
|
||||
2. **\<ul** id="father"**\>**
|
||||
|
||||
3. **\<li** id="first"**\>**大娃**\</li\>**
|
||||
|
||||
4. **\<li\>**二娃**\</li\>**
|
||||
|
||||
5. **\</ul\>**
|
||||
|
||||
6. **\<input** type="button" id="replace-btn" value="replace"**\>**
|
||||
|
||||
7. **\<script** type="text/javascript"**\>**
|
||||
|
||||
8. function replacenode(){
|
||||
|
||||
9. var oldnode = document.getElementById("first");
|
||||
|
||||
10. var newnode = document.createElement("li");
|
||||
|
||||
11. newnode.innerHTML = "金刚葫芦娃";
|
||||
|
||||
12. oldnode.parentNode.replaceChild(newnode, oldnode);
|
||||
|
||||
13. }
|
||||
|
||||
14. var replace = document.getElementById("replace-btn");
|
||||
|
||||
15. replace.onclick = replacenode;
|
||||
|
||||
16. **\</script\>**
|
||||
|
||||
17. **\</body\>\</span\>**
|
||||
155
JavaScript/教程/DOM简介.md
Normal file
@@ -0,0 +1,155 @@
|
||||
\>DOM树(document_object_moudule)
|
||||
|
||||

|
||||
|
||||
\>\>DOM定义
|
||||
|
||||
是w3c文档对象模型,是中立于平台和语言的接口,它允许程序和脚本动态的访问和更新文档内容、结构和样式。
|
||||
|
||||
\>\>DOM的组成
|
||||
|
||||
- 核心 DOM - 针对任何结构化文档的标准模型
|
||||
|
||||
- XML DOM - 针对 XML 文档的标准模型
|
||||
|
||||
- HTML DOM - 针对 HTML 文档的标准模型
|
||||
|
||||
\>DOM节点(通过结点树的方法指明了各个元素之间的关系)
|
||||
|
||||
\>\>文档节点、元素节点、文本节点、属性节点、注释节点
|
||||
|
||||
\>\>所有的结点都可以通过JS进行访问、所有的HTML元素节点都可以别修改,也可以创建删除节点
|
||||
|
||||
\>\>节点关系
|
||||
|
||||
- 再节点树中,顶端点被称为根
|
||||
|
||||
- 每个节点都有父节点
|
||||
|
||||
- 一个节点可拥有任意数量的子节点
|
||||
|
||||
- 同胞是拥有相同父节点的结点
|
||||
|
||||
\>DOM方法(通过定义类的对象的方法,实现了访问结点)
|
||||
|
||||
\>\>编程接口
|
||||
|
||||
可以通过JS等脚本语言对HTML_DOM进行访问
|
||||
|
||||
所有的HTML元素都被定义为对象,而编程接口则是对象的方法和对象的属性
|
||||
|
||||
方法是能够执行的动作(添加或修改元素节点)
|
||||
|
||||
属性是能够获取或设置的值(节点的名称或内容)
|
||||
|
||||
\>\>常用的HTML_DOM方法和属性
|
||||
|
||||
方法:
|
||||
|
||||
访方法id,tagName,ClassName
|
||||
|
||||
修改方法修改内容、修改样式、修改属性、创建节点、删除节点。
|
||||
|
||||
修改内容
|
||||
|
||||
document.getElementById("p1").innerHTML="New text!";
|
||||
|
||||
修改样式
|
||||
|
||||
document.getElementById("p2").style.color="blue";
|
||||
|
||||
创建节点
|
||||
|
||||
var node=document.createTextNode("This is new.");
|
||||
|
||||
使用事件节点
|
||||
|
||||
\<input type="button" onclick="document.body.style.backgroundColor='lavender';"
|
||||
value="Change background color" /\>
|
||||
|
||||
添加元素
|
||||
|
||||
para.appendChild(node);
|
||||
|
||||
element.insertBefore(para,child);
|
||||
|
||||
删除元素
|
||||
|
||||
parent.removeChild(child);
|
||||
|
||||
替换元素
|
||||
|
||||
parent.replaceChild(para,child);
|
||||
|
||||
| 方法 | 描述 |
|
||||
|--------------------------|-----------------------------------------------------------------|
|
||||
| getElementById() | 返回带有指定 ID 的元素。 |
|
||||
| getElementsByTagName() | 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。 |
|
||||
| getElementsByClassName() | 返回包含带有指定类名的所有元素的节点列表。 |
|
||||
| appendChild() | 把新的子节点添加到指定节点。 |
|
||||
| removeChild() | 删除子节点。 |
|
||||
| replaceChild() | 替换子节点。 |
|
||||
| insertBefore() | 在指定的子节点前面插入新的子节点。 |
|
||||
| createAttribute() | 创建属性节点。 |
|
||||
| createElement() | 创建元素节点。 |
|
||||
| createTextNode() | 创建文本节点。 |
|
||||
| getAttribute() | 返回指定的属性值。 |
|
||||
| setAttribute() | 把指定属性设置或修改为指定的值。 |
|
||||
|
||||
属性:
|
||||
|
||||
innerHTML //元素节点的文本值
|
||||
|
||||
parentNode//元素节点的父节点
|
||||
|
||||
childNodes//元素节点的子节点
|
||||
|
||||
atrributes//元素节点的属性节点
|
||||
|
||||
nodeName属性规定节点的名称(只读)
|
||||
|
||||
nodeValue规定节点的值
|
||||
|
||||
nodeType属性返回节点的类型
|
||||
|
||||
| 元素类型 | NodeType |
|
||||
|----------|----------|
|
||||
| 元素 | 1 |
|
||||
| 属性 | 2 |
|
||||
| 文本 | 3 |
|
||||
| 注释 | 8 |
|
||||
| 文档 | 9 |
|
||||
|
||||
\>\>说一下自己的理解
|
||||
|
||||
在这里,将html中的各个部分解析成节点的概念,有助于通过结点树建立节点关系模型,非常好,而且简单。
|
||||
|
||||
然后,有将html中各个部分,定义成对象,并且定义了对象的属性和方法,能够很轻松的完成对元素的访问和操作。
|
||||
|
||||
提到对象,联系C++中的知识,可以知道,对象,主要包括数据成员和成员函数,前者就是对象的属性,后者是对象的方法。
|
||||
|
||||
然后再说一下这里的DOM的理解,文档对象模型。简单的说,就是讲整个html文档中的所有元素,定义成节点和对象的过程
|
||||
|
||||
并且通过这种定义,简化并且系统的表达了对html的访问和操作。
|
||||
|
||||
\>DOM中相关的事件
|
||||
|
||||
.onclick=function(){displayDate()};
|
||||
|
||||
onclick="displayDate()"
|
||||
|
||||
onload="checkCookies()"
|
||||
|
||||
onchange="upperCase()"
|
||||
|
||||
onmouseover onmouseout
|
||||
|
||||
onmousedown onmouseup
|
||||
|
||||
\>DOM
|
||||
|
||||
var x = document.getElementsByTagName("p")
|
||||
|
||||
返回是节点数组
|
||||
|
||||
x.length能返回数组的长度
|
||||
BIN
JavaScript/教程/media/04d4031de63e53c5addd72792a6b60bd.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
JavaScript/教程/media/0b65a5c473aad3b4addc35c7f1e79e89.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
JavaScript/教程/media/32ed381aeecf1527d86e15829f232641.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
JavaScript/教程/media/41b23d86a383cc654da42e8957b33725.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
JavaScript/教程/media/75813153285d5ceb04c812e98c3b33a1.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
JavaScript/教程/media/a287b11ce3f0470882a238120c33a6bb.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
162
JavaScript/教程/初识JavaScript.md
Normal file
@@ -0,0 +1,162 @@
|
||||
**\>变量与数据类型**
|
||||
|
||||
\>\>定义:JavaScript,是一种脚本语言(编程语言,用来控制软件应用程序,以文本(ASCIIS)形式保存,在需要时被调用进行解释或编译),广泛应用于客户端网页开发,现在服务端也有应用NODEJS。动态、弱类型、基于原型的语言。像大多数编程语言一样,有变量、类型、流程控制
|
||||
|
||||
\>\>变量名称规则:字母下划线或美元符开头,大小写敏感,不允许使用js的关键字或者保留字作为文件名(作为解释性语言的一大优势就是不用考虑变量类型,提前分配孔家,编译过程中,分配空间就行)
|
||||
|
||||
\>\>变量类型:整型,浮点型,字符型,字符串。
|
||||
|
||||
\>\>变量定义:var 变量名;
|
||||
|
||||
(感觉像是C的私生子,有些地方不是那么严格,更加灵活变通)
|
||||
|
||||
**\>变量运算**
|
||||
|
||||
\>\>自增自减运算
|
||||
|
||||
\>\>简化运算。
|
||||
|
||||
\>\>字符串之间可以直接进行加法运算,表示连接。
|
||||
|
||||
\>\>字符串可以和其它类型的变量加法,表示转换成字符串类型,并连接。
|
||||
|
||||
\>数组
|
||||
|
||||
\>\>用于存放多个各种类型的数据,便于访问
|
||||
|
||||
\>\>数组的定义:
|
||||
|
||||
var arr = new array()//参数是数组长度
|
||||
|
||||
var arr = [‘a','b','c'];//可以直接使用数组内的元素定义
|
||||
|
||||
\>\>数组支持嵌套,多重数组(有点类似于存有多种数据的广义表)
|
||||
|
||||
\>\>数组一定有length属性,arr.length等于键名中最大值加一。
|
||||
|
||||
\>\>数组的长度可以直接在定义数组的时候给出
|
||||
|
||||
\>\>数组的定义函数:参数可以是数组,也可以是变量初始化数组中的数据。
|
||||
|
||||
\>\>数组的长度可以在任意时候添加,不会出现越界,这就是解释性语言的好处。
|
||||
|
||||
**\>对象**
|
||||
|
||||
\>\>定义:带有自己的属性和方法的数据类型。含有多个键值对。
|
||||
|
||||
var o = {
|
||||
|
||||
p:"hello"
|
||||
|
||||
}
|
||||
|
||||
var 变量声明,o 变量名称,p 键名(属性名), hello 键值(属性值),
|
||||
冒号分隔。数据对象的大括号包含,最后加分号。当键名不符合标识符的条件时,必须加引号
|
||||
|
||||
\>\>创建语句:
|
||||
|
||||
var ogj1 = {};
|
||||
//大括号,只是声明了这是个对象,但不能说明这个对象属于哪一个类(类和类的对象的理念)
|
||||
|
||||
var obj2 = new Object(); //相当于调用对象的构造函数,然后形成一个新的对象
|
||||
|
||||
var obj3 = Object.create(null);//想当于调用一个已知对象的构造函数
|
||||
|
||||
\>\>对象的引用,如果不同的变量指向同一个对象,他们都称作这个对象的引用,也就是说这些对象指向同一个内存地址,修改其中一个变量的属性,会影响到其他的变量。
|
||||
|
||||
\>\>对象属性访的问方式: 对象名.对象的属性。objectName.propertyName //数据成员
|
||||
|
||||
\>\>对象方法的访问方式:objectName.methodName(); //成员函数
|
||||
|
||||
\>时间类的对象定义:
|
||||
|
||||
var now = new Data(); //定义了一个时间对象now
|
||||
|
||||
now.setTime(); // 设定时间
|
||||
|
||||
now.getTime(); //得到完整的时间
|
||||
|
||||
now.getFullYear(); //的到年份
|
||||
|
||||
now.getMonth(); //得到月份
|
||||
|
||||
now.getData(); //得到日期几号
|
||||
|
||||
now.getHours(); //得到小时
|
||||
|
||||
now.getMinutes(); //得到分钟
|
||||
|
||||
now.getSeconds(); //得到秒
|
||||
|
||||
now.getDay(); //星期
|
||||
|
||||
\>string类的 对象的使用
|
||||
|
||||
对象的定义:
|
||||
|
||||
var mystr = “i like javascript”;
|
||||
|
||||
var mystr = new String("some string");
|
||||
|
||||
对象的访问:
|
||||
|
||||
string.toUpperCase();
|
||||
|
||||
string.toLowerCase();
|
||||
|
||||
string.charAt(number); //返回指定的单个字符
|
||||
|
||||
string.indexOf(substring, startpos); //在字符串中寻找子串
|
||||
|
||||
string.split(separator, limit);
|
||||
//将字符串分割为字符串数组,separator是分割符,limit是分割次数
|
||||
|
||||
string.substring(startpos,stoppos);
|
||||
//截取子串,参数分别是起止下标(终止与stop-1)
|
||||
|
||||
string.substr(startpos, length);
|
||||
//截取指定长度的子串,参数分别是起始值、子串长度
|
||||
|
||||
\>Math对象(本身就是一个对象而不是类)
|
||||
|
||||
\>\>对象成员的使用
|
||||
|
||||
Math.PI //圆周率
|
||||
|
||||
Math.abs() //绝对值
|
||||
|
||||
Math.ceil()/floor()/round() //分别是向上取整,向下取整,四舍五入。
|
||||
|
||||
random(); //返回0到1之间的随机数(包含0不包含1)
|
||||
|
||||
Math.min() / Math.max(); //返回指定数值中最低值
|
||||
|
||||
\>数组类的对象使用
|
||||
|
||||
\>\>数组对象的定义方法:
|
||||
|
||||
var 数组名 = new Array();
|
||||
|
||||
var 数组名 = new Array();
|
||||
|
||||
var 数组名 = [元素1,元素2,元素3,,,,,]
|
||||
|
||||
\>\>数组对象的使用
|
||||
|
||||
数组名[下标] = 值
|
||||
|
||||
\>\>数组对象的属性
|
||||
|
||||
arr.length //数组的长度
|
||||
|
||||
arr.concat(arr1, arr2,arr3.....)
|
||||
//链接多个数组,不改变数组对象arr,返回值是多个数组的连续
|
||||
|
||||
arr.join(separator); //separator是指分割符。
|
||||
|
||||
arr.reverse(); //倒序,arr被改变
|
||||
|
||||
arr.slice(start, end);
|
||||
//返回子数组,不包含end,负数表示从末尾开始想前数,不修改原来的数组
|
||||
|
||||
arr.sort(方法函数); //如果不指定函数,按Unicode编码的顺序排列
|
||||
21
JavaScript/教程/对CSS的认识.md
Normal file
@@ -0,0 +1,21 @@
|
||||
\>css的三种样式的定义方法
|
||||
|
||||
\>\>标签选择:使用html标签,对html中所有标签起作用
|
||||
|
||||
.\>\>器类别选择器:.类名,调用时:class = “类名”。
|
||||
|
||||
\>\>ID选择器 \#id,调用时:id = “ID符号”
|
||||
|
||||
\>选择器的分类及关系
|
||||
|
||||
子代选择器:只能选择下一层的自带,使用\>来执行
|
||||
|
||||
后代选择器:也称包含选择器,选择特定元素或元素组的后代,中间用空格 隔开
|
||||
|
||||
伪类选择器:a:hover,a:link,a:visited,input:focus
|
||||
|
||||
通用选择器:\*匹配所有的代码
|
||||
|
||||
群组选择器:,使用逗号隔开,相同的样式属性的几个元素
|
||||
|
||||
相邻同胞选择器:+表示与前者相邻的后者的格式
|
||||
197
JavaScript/教程/浏览器对象.md
Normal file
@@ -0,0 +1,197 @@
|
||||
\>浏览器对象
|
||||
|
||||
\>\>以浏览器为对象,调用浏览器对象的属性和方法。如:window.setinterval(clock,
|
||||
100) and widow.navigator,可以省略window。
|
||||
|
||||
\>\>函数的参数是另外一个函数时,只写另外一个函数的名字(待定)。
|
||||
|
||||
\>计时器
|
||||
|
||||
\>\>分类:
|
||||
|
||||
> 一次性计时器:尽在指定的延迟时间后触发一次行为
|
||||
|
||||
> 间隔性触发计时器:每隔一定时间触发一次
|
||||
|
||||
\>\>常用函数:
|
||||
|
||||
> setTimeout(代码行为, 延时时间):制定的毫秒数后调用函数或计算表达式
|
||||
|
||||
> clearTinmeout(时间设定函数的ID):取消有setTimeout()设置的timeout
|
||||
|
||||
> setIntervel(代码, 交互时间):按照指定的周期来调用函数或计算表达式
|
||||
|
||||
> 代码:要调用的函数或执行的代码串(行为);交互时间:周期性执行行为的时间;返回值为函始时钟的id值。
|
||||
|
||||
> clearInterval(时间设定函数的ID):取消由setIntervel()设置的timeout
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
|
||||
1. **\<span** style="font-size:18px;"**\>\<body\>**
|
||||
|
||||
2. **\<input** type="text" id="clock" size="50"**\>**
|
||||
|
||||
3. **\<script** type="text/javascript"**\>**
|
||||
|
||||
4. function clock(){
|
||||
|
||||
5. var time = new Date();
|
||||
|
||||
6. var attime = time.getHours() + ':' + time.getMinutes() + ':' +
|
||||
time.getSeconds();
|
||||
|
||||
7. document.getElementById("clock").value = attime;
|
||||
|
||||
8.
|
||||
|
||||
9. }
|
||||
|
||||
10. setInterval(clock, 100);
|
||||
|
||||
11. **\</script\>**
|
||||
|
||||
12. **\</body\>\</span\>**
|
||||
|
||||
//实现了简单的时间及时输出
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
|
||||
1. **\<span** style="font-size:18px;"**\>\<body\>**
|
||||
|
||||
2. **\<input** type="text" id="clock"**\>**
|
||||
|
||||
3. **\<input** type="button" id="istart" value="Start"**\>**
|
||||
|
||||
4. **\<input** type="button" id="istop" value="Stop"**\>**
|
||||
|
||||
5. **\<script** type="text/javascript"**\>**
|
||||
|
||||
6. var setid;
|
||||
|
||||
7. var time;
|
||||
|
||||
8. var attime;
|
||||
|
||||
9. function clock(){
|
||||
|
||||
10. time = new Date();
|
||||
|
||||
11. attime = time.getHours() + ":" + time.getMinutes() + ":" +
|
||||
time.getSeconds();
|
||||
|
||||
12. document.getElementById("clock").value = attime;
|
||||
|
||||
13. }
|
||||
|
||||
14. var istart = document.getElementById("istart");
|
||||
|
||||
15. istart.onclick = function(){
|
||||
|
||||
16. setid = setInterval(clock, 100);
|
||||
|
||||
17. }
|
||||
|
||||
18. var istop = document.getElementById("istop");
|
||||
|
||||
19. istop.onclick = function(){
|
||||
|
||||
20. clearInterval(setid);
|
||||
|
||||
21. }
|
||||
|
||||
22. **\</script\>**
|
||||
|
||||
23. **\</body\>\</span\>**
|
||||
|
||||
根据setIntervel返回的id值取消时钟的设置。
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
|
||||
1. **\<span** style="font-size:18px;"**\>\<body\>**
|
||||
|
||||
2. **\<input** type="text" id="inum"**\>**
|
||||
|
||||
3. **\<input** type="button" id="ialt" value="Start"**\>**
|
||||
|
||||
4. **\<script** type="text/javascript"**\>**
|
||||
|
||||
5. var inum = document.getElementById("inum");
|
||||
|
||||
6. var ialt = document.getElementById("ialt");
|
||||
|
||||
7. ialt.onclick = function () {
|
||||
|
||||
8. setTimeout("inum.value = 1", 1000);
|
||||
|
||||
9. setTimeout("inum.value = 2", 2000);
|
||||
|
||||
10. setTimeout("inum.value = 3", 3000);
|
||||
|
||||
11. setTimeout("inum.value = 4", 4000);
|
||||
|
||||
12. setTimeout("alert('666')", 5000);
|
||||
|
||||
13. }
|
||||
|
||||
14. **\</script\>**
|
||||
|
||||
15. **\</body\>\</span\>**
|
||||
|
||||
//实现了settimeout的函数的调用,注意,器低一个参数值可以是函数,也可以是普通行为,上述代码即为普通行为,需要加引号,而函数只需要写函数名,没有参数的话可以不加括号。
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51890683)
|
||||
|
||||
1. **\<span** style="font-size:18px;"**\>\<body\>**
|
||||
|
||||
2. **\<input** type="text" id="count"**\>**
|
||||
|
||||
3. **\<input** type="button" id="istart" value="Start"**\>**
|
||||
|
||||
4. **\<input** type="button" id="istop" value="Stop"**\>**
|
||||
|
||||
5. **\<script** type="text/javascript"**\>**
|
||||
|
||||
6. var seti;
|
||||
|
||||
7. var num = 0;
|
||||
|
||||
8. function startCount(){
|
||||
|
||||
9. document.getElementById('count').value = num;
|
||||
|
||||
10. num = num + 1;
|
||||
|
||||
11. seti = setTimeout("startCount()", 1000);
|
||||
|
||||
12.
|
||||
|
||||
13. }
|
||||
|
||||
14. var istart = document.getElementById("istart");
|
||||
|
||||
15. istart.onclick = function (){
|
||||
|
||||
16. startCount();
|
||||
|
||||
17. }
|
||||
|
||||
18. var istop = document.getElementById("istop");
|
||||
|
||||
19. istop.onclick = function(){
|
||||
|
||||
20. clearTimeout(seti);
|
||||
|
||||
21. }
|
||||
|
||||
22. **\</script\>**
|
||||
|
||||
23. **\</body\>\</span\>**
|
||||
|
||||
//实现了按秒计数器,可以开始和结束。
|
||||
|
||||
PS:有一个不明白的地方,在代码执行的时候,发现setIntervel(clock,1000);setTimeout(“startCount()”,
|
||||
1000)两个时间设定同样是调用两个函数,前者直接使用了函数名,而后者却有引号,函数名和括号。为什么?
|
||||
39
JavaScript/教程/浏览器对象二.md
Normal file
@@ -0,0 +1,39 @@
|
||||
\>location对象
|
||||
|
||||
\>\>作用:用于获取或设置窗体的URL,并且可用于解析URL
|
||||
|
||||
\>\>语法:location.[属性\|方法]
|
||||
|
||||
\>\>对象属性:
|
||||
|
||||

|
||||
|
||||
\>\>对象方法:
|
||||
|
||||
> assign():加载新的文档
|
||||
|
||||
> reload():重新加载当前文档
|
||||
|
||||
> replace():用心的文档替换当前的文档
|
||||
|
||||
\>navigator对象
|
||||
|
||||
\>\>作用:包含浏览器信息和操作系统版本
|
||||
|
||||
\>\>对象属性
|
||||
|
||||

|
||||
|
||||
\>screen对象
|
||||
|
||||
\>\>作用:半酣了关于屏幕的信息,高度宽度、颜色深度
|
||||
|
||||
\>\>属性:
|
||||
|
||||
> screen.height:返回屏幕分辨率的高
|
||||
|
||||
> screen.whidth:返回屏幕分辨率的宽
|
||||
|
||||
> screen.availWidth:屏幕的宽度
|
||||
|
||||
> screen.availHeight:屏幕宽度
|
||||
61
JavaScript/教程/程序控制结构和函数.md
Normal file
@@ -0,0 +1,61 @@
|
||||
\>程序控制结构简写
|
||||
|
||||
\>\>if-else条件判断选择
|
||||
|
||||
if(判断条件){分支1}
|
||||
|
||||
else {分支2}
|
||||
|
||||
\>\>switch多项选择结构,注意关键字default、break;
|
||||
|
||||
switch(选择变量){
|
||||
|
||||
case 1:分支1;break;
|
||||
|
||||
case 2:分支2;break;
|
||||
|
||||
case 3:分支3break;
|
||||
|
||||
default:分支4
|
||||
|
||||
}
|
||||
|
||||
\>\>for(初始化;循环条件;循环控制){
|
||||
|
||||
循环体;
|
||||
|
||||
}
|
||||
|
||||
\>\>while(判断语句){循环体}
|
||||
|
||||
\>\>关键字continue(退出本次循环开始新的循环)
|
||||
|
||||
\>\>关键字break(退出整个循环)
|
||||
|
||||
\>JS中的函数
|
||||
|
||||
\>\>函数的定义:
|
||||
|
||||
function fun(){函数体}
|
||||
|
||||
\>\>函数调用
|
||||
|
||||
函数名(实际参数);
|
||||
|
||||
\>\>参数传递
|
||||
|
||||
可以传递任意数量的参数, 不用声明参数类型
|
||||
|
||||
\>\>函数返回值
|
||||
|
||||
可以返回任意类型的返回值。
|
||||
|
||||
\>\>函数声明,是函数在任何地方都可以定义
|
||||
|
||||
\>\>函数作用域,全局函数,对象的函数
|
||||
|
||||
\>\>this:函数体中this说明当前函数方法的作用域。可以是全局作用域,可以是整个windows对象,可能用于指向函数外部的变量。
|
||||
|
||||
\>\>call(this的指向, 变量):可以改变当前函数中this的指向
|
||||
|
||||
\>\>apply(this的指向,数组):改变当前函数中this的指向
|
||||
482
JavaScript/教程/网页交互事件.md
Normal file
@@ -0,0 +1,482 @@
|
||||
\>JS与HTML的关联
|
||||
|
||||
**\>\>**内部关联:
|
||||
|
||||
> \<script type = "text/javascript"\>
|
||||
|
||||
> javascript 语言
|
||||
|
||||
> \</script\>
|
||||
|
||||
**\>\>**位置:对页面初始化的JS必须放在开头。
|
||||
|
||||
> 通过事件调用执行的JS对位置没有特殊要求
|
||||
|
||||
**\>\>**外部关联:
|
||||
|
||||
> 定义一个.js文件
|
||||
|
||||
> \<script src = "script.js"\>
|
||||
|
||||
> \</script\>
|
||||
|
||||
\>JS与事件绑定
|
||||
|
||||
**\>\>**间接绑定(函数名绑定):元素.事件 = 函数名;
|
||||
|
||||
> 将想要出发的行为写在一个函数里面,然后再将这个函数名赋值给元素的事件属性。
|
||||
|
||||
> 在这里共提到三个名词:
|
||||
|
||||
> 元素——指网页上的一个时间单位
|
||||
|
||||
> 事件——指发生在元素身上的事(作为元素的一个属性)
|
||||
|
||||
> 行为——指发生时间后带来的动作后果(写在了函数里)
|
||||
|
||||
> function func(){}
|
||||
|
||||
> btn.onclick = func;
|
||||
|
||||
**\>\>**直接绑定(匿名函数绑定):元素.事件 = function(){函数体}
|
||||
|
||||
> 将想要出发的行为,直接作为事件的函数。
|
||||
|
||||
> btn.onclick = function(){};
|
||||
|
||||
**\>\>**前者适合单一行为的绑定,后者适合多行为绑定和带参数函数行为的绑定。
|
||||
|
||||
\>JS对网页的操作
|
||||
|
||||
**\>\>**document.write()//直接向HTML中写内容
|
||||
|
||||
**\>\>**alert(字符串变量)//弹窗,在点击“确定”按钮前不能进行其他任何操作。通常用于调试程序。
|
||||
|
||||
**\>\>**doucument.getElementById("id_value")//通过id获取元素(具有唯一性),id_value为id属性的值
|
||||
|
||||
> 简单说,就是通过函数获取某个元素的id赋值给JS自身的变量,然后对这个id的变量进行操作,就相当于对HTML标签进行操作。
|
||||
|
||||
**\>\>**doucument.getElementsByTagName(TagName)//返回带有制定标签名的元素对象的集合(一个数组)。返回元素的顺序,使他们在文档中出现的顺序。TagName,是HTML标签。
|
||||
|
||||
**\>\>**id.innerHTML 或 TagName.innerName//可以返回显示标签内部的内容。
|
||||
|
||||
**\>\>**id.value 或 TagName.value//访问input的标签的值
|
||||
|
||||
\>鼠标事件
|
||||
|
||||
**\>\>**元素.onclick = 函数名;鼠标单击事件,某个元素的onclick属性。
|
||||
|
||||
**[html]** [view plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. **\<span** style="font-size:18px;"**\>\<body\>**
|
||||
|
||||
2. **\<p** id="pid"**\>**JavaScript**\</p\>**
|
||||
|
||||
3. **\<button** id="btn"**\>**click**\</button\>**
|
||||
|
||||
4. **\<script** type="text/javascript"**\>**
|
||||
|
||||
5. var btn = document.getElementById("btn");
|
||||
|
||||
6. btn.onclick = hello;
|
||||
|
||||
7. function hello(){
|
||||
|
||||
8. var pid = document.getElementById("pid");
|
||||
|
||||
9. pid.innerHTML = "Hello!";
|
||||
|
||||
10. }
|
||||
|
||||
11. **\</script\>**
|
||||
|
||||
12. **\</body\>\</span\>**
|
||||
|
||||
//有一个botton对象,id为btn,这是元素
|
||||
|
||||
//修改btn.onclick属性为函数hello,这是触发事件与行为的联系。
|
||||
|
||||
//函数hello执行的时候将id为pid的标签内容修改,这是行为
|
||||
|
||||
**\>\>**鼠标动作
|
||||
|
||||
> onclick 鼠标点击
|
||||
|
||||
> onmousedown 鼠标按下
|
||||
|
||||
> onmouseup 鼠标松开
|
||||
|
||||
> onmouseover 鼠标悬停
|
||||
|
||||
> onmouseout 鼠标离开
|
||||
|
||||
> onmouseup & onmousedown
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<p id="pid"\>JavaScript\</p\>
|
||||
|
||||
3. \<button id="btn"\>click\</button\>
|
||||
|
||||
4. \<script type="text/javascript"\>
|
||||
|
||||
5. var btn = document.getElementById("btn");
|
||||
|
||||
6. btn.onmousedown = down;
|
||||
|
||||
7. btn.onmouseup = up;
|
||||
|
||||
8. function up() {
|
||||
|
||||
9. var pid = document.getElementById("pid");
|
||||
|
||||
10. pid.innerHTML = "up";
|
||||
|
||||
11. }
|
||||
|
||||
12. function down() {
|
||||
|
||||
13. var pid = document.getElementById("pid");
|
||||
|
||||
14. pid.innerHTML = "down";
|
||||
|
||||
15. }
|
||||
|
||||
16. \</script\>
|
||||
|
||||
17. \</body\>\</span\>
|
||||
|
||||
> onmouseover & onmouseout
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<p id="pid"\>JavaScript\</p\>
|
||||
|
||||
3. \<button id="btn"\>click\</button\>
|
||||
|
||||
4. \<script type="text/javascript"\>
|
||||
|
||||
5. var btn = document.getElementById("btn");
|
||||
|
||||
6. btn.onmouseover = over;
|
||||
|
||||
7. btn.onmouseout = out;
|
||||
|
||||
8. function over() {
|
||||
|
||||
9. var pid = document.getElementById("pid");
|
||||
|
||||
10. pid.innerHTML = "over";
|
||||
|
||||
11. }
|
||||
|
||||
12. function out() {
|
||||
|
||||
13. var pid = document.getElementById("pid");
|
||||
|
||||
14. pid.innerHTML = "out";
|
||||
|
||||
15. }
|
||||
|
||||
16. \</script\>
|
||||
|
||||
17. \</body\>\</span\>
|
||||
|
||||
\>文本框事件
|
||||
|
||||
> onfocus 输入框聚焦
|
||||
|
||||
> onblur 输入框模糊
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<p id="pid"\>JavaScript\</p\>
|
||||
|
||||
3. \<input id="input"\>
|
||||
|
||||
4. \<script type="text/javascript"\>
|
||||
|
||||
5. var inp = document.getElementById("input");
|
||||
|
||||
6. inp.onfocus = focus;
|
||||
|
||||
7. inp.onblur = blur;
|
||||
|
||||
8. function focus() {
|
||||
|
||||
9. var pid = document.getElementById("pid");
|
||||
|
||||
10. pid.innerHTML = "focus";
|
||||
|
||||
11. }
|
||||
|
||||
12. function blur() {
|
||||
|
||||
13. var pid = document.getElementById("pid");
|
||||
|
||||
14. pid.innerHTML = "blur";
|
||||
|
||||
15. }
|
||||
|
||||
16. \</script\>
|
||||
|
||||
17. \</body\>\</span\>
|
||||
|
||||
onselect文本框被选中
|
||||
|
||||
onchange 改变文本框的内容出发事件
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<p id="pid"\>JavaScript\</p\>
|
||||
|
||||
3. \<input id="input" value="change me\~"\>
|
||||
|
||||
4. \<script type="text/javascript"\>
|
||||
|
||||
5. var inp = document.getElementById("input");
|
||||
|
||||
6. inp.onselect = select;
|
||||
|
||||
7. inp.onchange = change;
|
||||
|
||||
8. function select() {
|
||||
|
||||
9. var pid = document.getElementById("pid");
|
||||
|
||||
10. pid.innerHTML = "select";
|
||||
|
||||
11. }
|
||||
|
||||
12. function change() {
|
||||
|
||||
13. var pid = document.getElementById("pid");
|
||||
|
||||
14. pid.innerHTML = "change";
|
||||
|
||||
15. }
|
||||
|
||||
16. \</script\>
|
||||
|
||||
17. \</body\>\</span\>
|
||||
|
||||
**\>\>**确认框
|
||||
|
||||
> 语法:confirm(str)
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<input id="input" type="button" value="点击我"\>
|
||||
|
||||
3. \<script type="text/javascript"\>
|
||||
|
||||
4. function rec(){
|
||||
|
||||
5. var message = confirm("Do you like me?");
|
||||
|
||||
6. **if**(message == true)
|
||||
|
||||
7. {
|
||||
|
||||
8. document.write("么么哒!\~");
|
||||
|
||||
9. }
|
||||
|
||||
10. **else**
|
||||
|
||||
11. {
|
||||
|
||||
12. document.write("泥奏凯!");
|
||||
|
||||
13. }
|
||||
|
||||
14. }
|
||||
|
||||
15. var inp = document.getElementById("input");
|
||||
|
||||
16. inp.onclick = rec;
|
||||
|
||||
17. \</script\>
|
||||
|
||||
18. \</body\>\</span\>
|
||||
|
||||
**\>\>**提问框
|
||||
|
||||
> 语法:prompt(str1,str2)
|
||||
|
||||
> 说明:str1显示在消息对话框中不可修改;str2显示在文本框中的默认内容可修改
|
||||
|
||||
> 返回值:确定-\>返回文本框中输入的内容;取消-\>返回null
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<input id="input" type="button" value="点击我"\>
|
||||
|
||||
3. \<script type="text/javascript"\>
|
||||
|
||||
4. function rec(){
|
||||
|
||||
5. var score; // score变量,用来存储用户输入的成绩值。
|
||||
|
||||
6. score = prompt("Your score?");
|
||||
|
||||
7. **if**(score \>= 90)
|
||||
|
||||
8. {
|
||||
|
||||
9. document.write("你很棒!");
|
||||
|
||||
10. }
|
||||
|
||||
11. **else** **if**(score \>= 75)
|
||||
|
||||
12. {
|
||||
|
||||
13. document.write("不错哦!");
|
||||
|
||||
14. }
|
||||
|
||||
15. **else** **if**(score \>= 60)
|
||||
|
||||
16. {
|
||||
|
||||
17. document.write("要加油!");
|
||||
|
||||
18. }
|
||||
|
||||
19. **else**
|
||||
|
||||
20. {
|
||||
|
||||
21. document.write("要努力了哦!");
|
||||
|
||||
22. }
|
||||
|
||||
23. }
|
||||
|
||||
24. var inp = document.getElementById("input");
|
||||
|
||||
25. inp.onclick = rec;
|
||||
|
||||
26. \</script\>
|
||||
|
||||
27. \</body\>\</span\>
|
||||
|
||||
\>网页的属性设置
|
||||
|
||||
**\>\>**element.getAttribute(name)//element是待设定元素对象id或者标签名,name是属性的名字。
|
||||
|
||||
**\>\>**element.setAttribute(name,value)//element是id或者标签的名字(待设定元素对象),name是属性名,value是新的属性值
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<p id="pid" title="JavaScript"\>JavaScript\</p\>
|
||||
|
||||
3. \<button id="btn"\>click\</button\>
|
||||
|
||||
4. \<script type="text/javascript"\>
|
||||
|
||||
5. var btn = document.getElementById("btn");
|
||||
|
||||
6. btn.onclick = attr;
|
||||
|
||||
7. function attr() {
|
||||
|
||||
8. var pid = document.getElementById("pid");
|
||||
|
||||
9. alert(pid.getAttribute("id"));
|
||||
|
||||
10. alert(pid.getAttribute("title"));
|
||||
|
||||
11. pid.setAttribute("title", "hello");
|
||||
|
||||
12. alert(pid.getAttribute("title"));
|
||||
|
||||
13. }
|
||||
|
||||
14. \</script\>
|
||||
|
||||
15. \</body\>\</span\>
|
||||
|
||||
**\>\>**window.open(URL,\<窗口方式\>,\<参数字符串\>)//URL打开的网址路径,打开方式可以是"_top",
|
||||
"_blank", "_self"。
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<body\>
|
||||
|
||||
2. \<input id="input" type="button" value="点击我,打开新窗口!"\>
|
||||
|
||||
3. \<script type="text/javascript"\>
|
||||
|
||||
4. function windowOpen(){
|
||||
|
||||
5. window.open('http://www.jisuanke.com', '_blank', 'width = 600, height = 400,
|
||||
top = 100, left = 0');
|
||||
|
||||
6. }
|
||||
|
||||
7. var inp = document.getElementById("input");
|
||||
|
||||
8. inp.onclick = windowOpen;
|
||||
|
||||
9. \</script\>
|
||||
|
||||
10. \</body\>\</span\>
|
||||
|
||||
**\>\>**windows.onload 当页面加载或者刷新时会出现相应的函数。
|
||||
|
||||
**[python]** [view
|
||||
plain](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
[copy](http://blog.csdn.net/estom_yin/article/details/51888110)
|
||||
|
||||
1. \<span style="font-size:18px;"\>\<head\>
|
||||
|
||||
2. \<meta charset="UTF-8"\>
|
||||
|
||||
3. \<title\>load\</title\>
|
||||
|
||||
4. \<script type="text/javascript"\>
|
||||
|
||||
5. window.onload = load;
|
||||
|
||||
6. function load() {
|
||||
|
||||
7. alert("load");
|
||||
|
||||
8. }
|
||||
|
||||
9. \</script\>
|
||||
|
||||
10. \</head\>\</span\>
|
||||
138
算法/补充/Bellman-Ford 单源最短路径算法.md
Normal file
@@ -0,0 +1,138 @@
|
||||
Bellman-Ford 单源最短路径算法
|
||||
|
||||
Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source
|
||||
Shortest Path)的算法。该算法由 Richard Bellman 和 Lester Ford 分别发表于 1958
|
||||
年和 1956 年,而实际上 Edward F. Moore 也在 1957
|
||||
年发布了相同的算法,因此,此算法也常被称为 Bellman-Ford-Moore 算法。
|
||||
|
||||
Bellman-Ford 算法和 [Dijkstra
|
||||
算法](http://www.cnblogs.com/gaochundong/p/dijkstra_algorithm.html)同为解决单源最短路径的算法。对于带权有向图
|
||||
G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 [Bellman-Ford
|
||||
算法](http://www.cnblogs.com/gaochundong/p/bellman_ford_algorithm.html)能适应一般的情况(即存在负权边的情况)。一个实现的很好的
|
||||
Dijkstra 算法比 Bellman-Ford 算法的运行时间要低。
|
||||
|
||||
Bellman-Ford 算法采用动态规划(Dynamic Programming)进行设计,实现的时间复杂度为
|
||||
O(V\*E),其中 V 为顶点数量,E 为边的数量。Dijkstra 算法采用贪心算法(Greedy
|
||||
Algorithm)范式进行设计,普通实现的时间复杂度为 O(V2),若基于 [Fibonacci
|
||||
heap](http://www.cnblogs.com/gaochundong/p/fibonacci_heap.html)
|
||||
的最小优先队列实现版本则时间复杂度为 O(E + VlogV)。
|
||||
|
||||
Bellman-Ford 算法描述:
|
||||
|
||||
1. 创建源顶点 v 到图中所有顶点的距离的集合
|
||||
distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
|
||||
|
||||
2. 计算最短路径,执行 V - 1 次遍历;
|
||||
|
||||
- 对于图中的每条边:如果起点 u 的距离 d 加上边的权值 w 小于终点 v 的距离
|
||||
d,则更新终点 v 的距离值 d;
|
||||
|
||||
3. 检测图中是否有负权边形成了环,遍历图中的所有边,计算 u 至 v 的距离,如果对于
|
||||
v 存在更小的距离,则说明存在环;
|
||||
|
||||
伪码实现如下:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 BELLMAN-FORD(G, w, s) 2 INITIALIZE-SINGLE-SOURCE(G, s) 3 for i 1 to \|V[G]\| -
|
||||
14 do for each edge (u, v) E[G] 5 do RELAX(u, v, w) 6 for each edge (u, v) E[G]
|
||||
7 do if d[v] \> d[u] + w(u, v) 8 then return FALSE 9 return TRUE
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
Bellman-Ford 算法的运行时间为 O(V\*E),因为第 2 行的初始化占用了 Θ(V),第 3-4
|
||||
行对边进行了 V - 1 趟操作,每趟操作的运行时间为 Θ(E)。第 6-7 行的 for
|
||||
循环运行时间为 O(E)。
|
||||
|
||||
例如,下面的有向图 G 中包含 5 个顶点和 8 条边。假设源点 为 A。初始化 distSet
|
||||
所有距离为 INFI,源点 A 为 0。
|
||||
|
||||

|
||||
|
||||
由于图中有 5 个顶点,按照步骤 1 需要遍历 4 次,第一次遍历的结果如下。
|
||||
|
||||

|
||||
|
||||
第二次遍历的结果如下。
|
||||
|
||||

|
||||
|
||||
以此类推可以得出完全遍历的结果。
|
||||
|
||||
C\# 代码实现:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 5
|
||||
namespace GraphAlgorithmTesting 6 { 7 class Program 8 { 9 static void
|
||||
Main(string[] args) 10 { 11 int[,] graph = new int[9, 9] 12 { 13 {0, 4, 0, 0, 0,
|
||||
0, 0, 8, 0}, 14 {4, 0, 8, 0, 0, 0, 0, 11, 0}, 15 {0, 8, 0, 7, 0, 4, 0, 0, 2}, 16
|
||||
{0, 0, 7, 0, 9, 14, 0, 0, 0}, 17 {0, 0, 0, 9, 0, 10, 0, 0, 0}, 18 {0, 0, 4, 0,
|
||||
10, 0, 2, 0, 0}, 19 {0, 0, 0, 14, 0, 2, 0, 1, 6}, 20 {8, 11, 0, 0, 0, 0, 1, 0,
|
||||
7}, 21 {0, 0, 2, 0, 0, 0, 6, 7, 0} 22 }; 23 24 Graph g = new
|
||||
Graph(graph.GetLength(0)); 25 for (int i = 0; i \< graph.GetLength(0); i++) 26 {
|
||||
27 for (int j = 0; j \< graph.GetLength(1); j++) 28 { 29 if (graph[i, j] \> 0)
|
||||
30 g.AddEdge(i, j, graph[i, j]); 31 } 32 } 33 34 Console.WriteLine("Graph Vertex
|
||||
Count : {0}", g.VertexCount); 35 Console.WriteLine("Graph Edge Count : {0}",
|
||||
g.EdgeCount); 36 Console.WriteLine(); 37 38 int[] distSet = g.BellmanFord(0); 39
|
||||
Console.WriteLine("Vertex\\t\\tDistance from Source"); 40 for (int i = 0; i \<
|
||||
distSet.Length; i++) 41 { 42 Console.WriteLine("{0}\\t\\t{1}", i, distSet[i]);
|
||||
43 } 44 45 // build a directed and negative weighted graph 46 Graph
|
||||
directedGraph = new Graph(5); 47 directedGraph.AddEdge(0, 1, -1); 48
|
||||
directedGraph.AddEdge(0, 2, 4); 49 directedGraph.AddEdge(1, 2, 3); 50
|
||||
directedGraph.AddEdge(1, 3, 2); 51 directedGraph.AddEdge(1, 4, 2); 52
|
||||
directedGraph.AddEdge(3, 2, 5); 53 directedGraph.AddEdge(3, 1, 1); 54
|
||||
directedGraph.AddEdge(4, 3, -3); 55 56 Console.WriteLine(); 57
|
||||
Console.WriteLine("Graph Vertex Count : {0}", directedGraph.VertexCount); 58
|
||||
Console.WriteLine("Graph Edge Count : {0}", directedGraph.EdgeCount); 59
|
||||
Console.WriteLine(); 60 61 int[] distSet1 = directedGraph.BellmanFord(0); 62
|
||||
Console.WriteLine("Vertex\\t\\tDistance from Source"); 63 for (int i = 0; i \<
|
||||
distSet1.Length; i++) 64 { 65 Console.WriteLine("{0}\\t\\t{1}", i, distSet1[i]);
|
||||
66 } 67 68 Console.ReadKey(); 69 } 70 71 class Edge 72 { 73 public Edge(int
|
||||
begin, int end, int weight) 74 { 75 this.Begin = begin; 76 this.End = end; 77
|
||||
this.Weight = weight; 78 } 79 80 public int Begin { get; private set; } 81
|
||||
public int End { get; private set; } 82 public int Weight { get; private set; }
|
||||
83 84 public override string ToString() 85 { 86 return string.Format( 87
|
||||
"Begin[{0}], End[{1}], Weight[{2}]", 88 Begin, End, Weight); 89 } 90 } 91 92
|
||||
class Graph 93 { 94 private Dictionary\<int, List\<Edge\>\> \_adjacentEdges 95 =
|
||||
new Dictionary\<int, List\<Edge\>\>(); 96 97 public Graph(int vertexCount) 98 {
|
||||
99 this.VertexCount = vertexCount;100 } 101 102 public int VertexCount { get;
|
||||
private set; }103 104 public int EdgeCount 105 { 106 get107 { 108 return
|
||||
\_adjacentEdges.Values.SelectMany(e =\> e).Count(); 109 } 110 } 111 112 public
|
||||
void AddEdge(int begin, int end, int weight) 113 { 114 if
|
||||
(!\_adjacentEdges.ContainsKey(begin)) 115 { 116 var edges = new List\<Edge\>();
|
||||
117 \_adjacentEdges.Add(begin, edges); 118 } 119 120
|
||||
\_adjacentEdges[begin].Add(new Edge(begin, end, weight)); 121 } 122 123 public
|
||||
int[] BellmanFord(int source) 124 { 125 // distSet[i] will hold the shortest
|
||||
distance from source to i126 int[] distSet = new int[VertexCount];127 128 //
|
||||
Step 1: Initialize distances from source to all other vertices as INFINITE129
|
||||
for (int i = 0; i \< VertexCount; i++)130 { 131 distSet[i] = int.MaxValue;132 }
|
||||
133 distSet[source] = 0;134 135 // Step 2: Relax all edges \|V\| - 1 times. A
|
||||
simple shortest path from source136 // to any other vertex can have at-most
|
||||
\|V\| - 1 edges137 for (int i = 1; i \<= VertexCount - 1; i++)138 { 139 foreach
|
||||
(var edge in \_adjacentEdges.Values.SelectMany(e =\> e)) 140 { 141 int u =
|
||||
edge.Begin; 142 int v = edge.End; 143 int weight = edge.Weight; 144 145 if
|
||||
(distSet[u] != int.MaxValue146 && distSet[u] + weight \< distSet[v]) 147 { 148
|
||||
distSet[v] = distSet[u] + weight; 149 } 150 } 151 } 152 153 // Step 3: check for
|
||||
negative-weight cycles. The above step guarantees154 // shortest distances if
|
||||
graph doesn't contain negative weight cycle.155 // If we get a shorter path,
|
||||
then there is a cycle.156 foreach (var edge in
|
||||
\_adjacentEdges.Values.SelectMany(e =\> e)) 157 { 158 int u = edge.Begin; 159
|
||||
int v = edge.End; 160 int weight = edge.Weight; 161 162 if (distSet[u] !=
|
||||
int.MaxValue163 && distSet[u] + weight \< distSet[v]) 164 { 165
|
||||
Console.WriteLine("Graph contains negative weight cycle.");166 } 167 } 168 169
|
||||
return distSet; 170 } 171 } 172 } 173 }
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
运行结果如下:
|
||||
|
||||

|
||||
196
算法/补充/Dijkstra 单源最短路径算法.md
Normal file
@@ -0,0 +1,196 @@
|
||||
Dijkstra 单源最短路径算法
|
||||
|
||||
Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source
|
||||
Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年构思并于 1959
|
||||
年发表。其解决的问题是:给定图 G 和源顶点 v,找到从 v 至图中所有顶点的最短路径。
|
||||
|
||||

|
||||
|
||||
Dijkstra 算法采用贪心算法(Greedy
|
||||
Algorithm)范式进行设计。在最短路径问题中,对于带权有向图 G = (V, E),Dijkstra
|
||||
算法的初始实现版本未使用最小优先队列实现,其时间复杂度为 O(V2),基于 [Fibonacci
|
||||
heap](http://www.cnblogs.com/gaochundong/p/fibonacci_heap.html)
|
||||
的最小优先队列实现版本,其时间复杂度为 O(E + VlogV)。
|
||||
|
||||

|
||||
|
||||
[Bellman-Ford
|
||||
算法](http://www.cnblogs.com/gaochundong/p/bellman_ford_algorithm.html)和
|
||||
[Dijkstra
|
||||
算法](http://www.cnblogs.com/gaochundong/p/dijkstra_algorithm.html)同为解决单源最短路径的算法。对于带权有向图
|
||||
G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 Bellman-Ford
|
||||
算法能适应一般的情况(即存在负权边的情况)。一个实现的很好的 Dijkstra 算法比
|
||||
Bellman-Ford 算法的运行时间 O(V\*E) 要低。
|
||||
|
||||
Dijkstra 算法描述:
|
||||
|
||||
1. 创建源顶点 v 到图中所有顶点的距离的集合
|
||||
distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
|
||||
|
||||
2. 创建 SPT(Shortest Path Tree)集合 sptSet,用于存放包含在 SPT 中的顶点;
|
||||
|
||||
3. 如果 sptSet 中并没有包含所有的顶点,则:
|
||||
|
||||
- 选中不包含在 sptSet 中的顶点 u,u 为当前 sptSet 中未确认的最短距离顶点;
|
||||
|
||||
- 将 u 包含进 sptSet;
|
||||
|
||||
- 更新 u 的所有邻接顶点的距离值;
|
||||
|
||||
伪码实现如下:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 function Dijkstra(Graph, source): 2 3 dist[source] ← 0 // Distance from source
|
||||
to source 4 prev[source] ← undefined // Previous node in optimal path
|
||||
initialization 5 6 for each vertex v in Graph: // Initialization 7 if v ≠ source
|
||||
// Where v has not yet been removed from Q (unvisited nodes) 8 dist[v] ←
|
||||
infinity // Unknown distance function from source to v 9 prev[v] ← undefined //
|
||||
Previous node in optimal path from source 10 end if 11 add v to Q // All nodes
|
||||
initially in Q (unvisited nodes) 12 end for13 14 while Q is not empty: 15 u ←
|
||||
vertex in Q with min dist[u] // Source node in first case16 remove u from Q 17
|
||||
18 for each neighbor v of u: // where v has not yet been removed from Q. 19 alt
|
||||
← dist[u] + length(u, v) 20 if alt \< dist[v]: // A shorter path to v has been
|
||||
found 21 dist[v] ← alt 22 prev[v] ← u 23 end if24 end for25 end while26 27
|
||||
return dist[], prev[] 28 29 end function
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
例如,下面是一个包含 9 个顶点的图,每条边分别标识了距离。
|
||||
|
||||

|
||||
|
||||
源顶点 source = 0,初始时,
|
||||
|
||||
- sptSet = {false, false, false, false, false, false, false, false, false};
|
||||
|
||||
- distSet = {**0**, INF, INF, INF, INF, INF, INF, INF, INF};
|
||||
|
||||
将 0 包含至 sptSet 中;
|
||||
|
||||
- sptSet = {**true**, false, false, false, false, false, false, false, false};
|
||||
|
||||
更新 0 至其邻接节点的距离;
|
||||
|
||||
- distSet = {**0**, **4**, INF, INF, INF, INF, INF, **8**, INF};
|
||||
|
||||

|
||||
|
||||
选择不在 sptSet 中的 Min Distance 的顶点,为顶点 1,则将 1 包含至 sptSet;
|
||||
|
||||
- sptSet = {**true**, **true**, false, false, false, false, false, false,
|
||||
false};
|
||||
|
||||
更新 1 至其邻接节点的距离;
|
||||
|
||||
- distSet = {**0**, **4**, **12**, INF, INF, INF, INF, **8**, INF};
|
||||
|
||||

|
||||
|
||||
选择不在 sptSet 中的 Min Distance 的顶点,为顶点 7,则将 7 包含至 sptSet;
|
||||
|
||||
- sptSet = {**true**, **true**, false, false, false, false, false, **true**,
|
||||
false};
|
||||
|
||||
更新 7 至其邻接节点的距离;
|
||||
|
||||
- distSet = {**0**, **4**, **12**, INF, INF, INF, **9**, **8**, **15**};
|
||||
|
||||

|
||||
|
||||
选择不在 sptSet 中的 Min Distance 的顶点,为顶点 6,则将 6 包含至 sptSet;
|
||||
|
||||
- sptSet = {**true**, **true**, false, false, false, false, **true**,
|
||||
**true**, false};
|
||||
|
||||
更新 6 至其邻接节点的距离;
|
||||
|
||||
- distSet = {**0**, **4**, **12**, INF, INF, **11**, **9**, **8**, **15**};
|
||||
|
||||

|
||||
|
||||
以此类推,直到遍历结束。
|
||||
|
||||
- sptSet = {**true**, **true**, **true**, **true**, **true**, **true**,
|
||||
**true**, **true**, **true**};
|
||||
|
||||
- distSet = {**0**, **4**, **12**, **19**, **21**, **11**, **9**, **8**,
|
||||
**14**};
|
||||
|
||||

|
||||
|
||||
最终结果为源顶点 0 至所有顶点的距离:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
Vertex Distance from Source 0 0 1 4 2 12 3 19 4 21 5 11 6 9 7 8 8 14
|
||||
|
||||
复制代码
|
||||
|
||||
C\#代码实现:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 5
|
||||
namespace GraphAlgorithmTesting 6 { 7 class Program 8 { 9 static void
|
||||
Main(string[] args) 10 { 11 int[,] graph = new int[9, 9] 12 { 13 {0, 4, 0, 0, 0,
|
||||
0, 0, 8, 0}, 14 {4, 0, 8, 0, 0, 0, 0, 11, 0}, 15 {0, 8, 0, 7, 0, 4, 0, 0, 2}, 16
|
||||
{0, 0, 7, 0, 9, 14, 0, 0, 0}, 17 {0, 0, 0, 9, 0, 10, 0, 0, 0}, 18 {0, 0, 4, 0,
|
||||
10, 0, 2, 0, 0}, 19 {0, 0, 0, 14, 0, 2, 0, 1, 6}, 20 {8, 11, 0, 0, 0, 0, 1, 0,
|
||||
7}, 21 {0, 0, 2, 0, 0, 0, 6, 7, 0} 22 }; 23 24 Graph g = new
|
||||
Graph(graph.GetLength(0)); 25 for (int i = 0; i \< graph.GetLength(0); i++) 26 {
|
||||
27 for (int j = 0; j \< graph.GetLength(1); j++) 28 { 29 if (graph[i, j] \> 0)
|
||||
30 g.AddEdge(i, j, graph[i, j]); 31 } 32 } 33 34 int[] dist = g.Dijkstra(0); 35
|
||||
Console.WriteLine("Vertex\\t\\tDistance from Source"); 36 for (int i = 0; i \<
|
||||
dist.Length; i++) 37 { 38 Console.WriteLine("{0}\\t\\t{1}", i, dist[i]); 39 } 40
|
||||
41 Console.ReadKey(); 42 } 43 44 class Edge 45 { 46 public Edge(int begin, int
|
||||
end, int distance) 47 { 48 this.Begin = begin; 49 this.End = end; 50
|
||||
this.Distance = distance; 51 } 52 53 public int Begin { get; private set; } 54
|
||||
public int End { get; private set; } 55 public int Distance { get; private set;
|
||||
} 56 } 57 58 class Graph 59 { 60 private Dictionary\<int, List\<Edge\>\>
|
||||
\_adjacentEdges 61 = new Dictionary\<int, List\<Edge\>\>(); 62 63 public
|
||||
Graph(int vertexCount) 64 { 65 this.VertexCount = vertexCount; 66 } 67 68 public
|
||||
int VertexCount { get; private set; } 69 70 public void AddEdge(int begin, int
|
||||
end, int distance) 71 { 72 if (!\_adjacentEdges.ContainsKey(begin)) 73 { 74 var
|
||||
edges = new List\<Edge\>(); 75 \_adjacentEdges.Add(begin, edges); 76 } 77 78
|
||||
\_adjacentEdges[begin].Add(new Edge(begin, end, distance)); 79 } 80 81 public
|
||||
int[] Dijkstra(int source) 82 { 83 // dist[i] will hold the shortest distance
|
||||
from source to i 84 int[] distSet = new int[VertexCount]; 85 86 // sptSet[i]
|
||||
will true if vertex i is included in shortest 87 // path tree or shortest
|
||||
distance from source to i is finalized 88 bool[] sptSet = new bool[VertexCount];
|
||||
89 90 // initialize all distances as INFINITE and stpSet[] as false 91 for (int
|
||||
i = 0; i \< VertexCount; i++) 92 { 93 distSet[i] = int.MaxValue; 94 sptSet[i] =
|
||||
false; 95 } 96 97 // distance of source vertex from itself is always 0 98
|
||||
distSet[source] = 0; 99 100 // find shortest path for all vertices101 for (int i
|
||||
= 0; i \< VertexCount - 1; i++)102 { 103 // pick the minimum distance vertex
|
||||
from the set of vertices not104 // yet processed. u is always equal to source in
|
||||
first iteration.105 int u = CalculateMinDistance(distSet, sptSet); 106 107 //
|
||||
mark the picked vertex as processed108 sptSet[u] = true;109 110 // update dist
|
||||
value of the adjacent vertices of the picked vertex.111 for (int v = 0; v \<
|
||||
VertexCount; v++)112 { 113 // update dist[v] only if is not in sptSet, there is
|
||||
an edge from114 // u to v, and total weight of path from source to v through u
|
||||
is115 // smaller than current value of dist[v]116 if (!sptSet[v] 117 &&
|
||||
distSet[u] != int.MaxValue118 && \_adjacentEdges[u].Exists(e =\> e.End == v))
|
||||
119 { 120 int d = \_adjacentEdges[u].Single(e =\> e.End == v).Distance; 121 if
|
||||
(distSet[u] + d \< distSet[v]) 122 { 123 distSet[v] = distSet[u] + d; 124 } 125
|
||||
} 126 } 127 } 128 129 return distSet; 130 } 131 132 /// \<summary\>133 /// A
|
||||
utility function to find the vertex with minimum distance value, 134 /// from
|
||||
the set of vertices not yet included in shortest path tree 135 ///
|
||||
\</summary\>136 private int CalculateMinDistance(int[] distSet, bool[]
|
||||
sptSet)137 { 138 int minDistance = int.MaxValue;139 int minDistanceIndex =
|
||||
\-1;140 141 for (int v = 0; v \< VertexCount; v++)142 { 143 if (!sptSet[v] &&
|
||||
distSet[v] \<= minDistance) 144 { 145 minDistance = distSet[v]; 146
|
||||
minDistanceIndex = v; 147 } 148 } 149 150 return minDistanceIndex; 151 } 152 }
|
||||
153 } 154 }
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
135
算法/补充/Floyd-Warshall 全源最短路径算法.md
Normal file
@@ -0,0 +1,135 @@
|
||||
Floyd-Warshall 全源最短路径算法
|
||||
|
||||
Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E)
|
||||
上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths
|
||||
Problem),其中图 G 允许存在权值为负的边,但不存在权值为负的回路。Floyd-Warshall
|
||||
算法的运行时间为 Θ(V3)。
|
||||
|
||||
Floyd-Warshall 算法由 Robert Floyd 于 1962 年提出,但其实质上与 Bernad Roy 于
|
||||
1959 年和 Stephen Warshall 于 1962 年提出的算法相同。
|
||||
|
||||
解决单源最短路径问题的方案有 [Dijkstra
|
||||
算法](http://www.cnblogs.com/gaochundong/p/dijkstra_algorithm.html)和
|
||||
[Bellman-Ford
|
||||
算法](http://www.cnblogs.com/gaochundong/p/bellman_ford_algorithm.html),对于全源最短路径问题可以认为是单源最短路径问题(Single
|
||||
Source Shortest Paths
|
||||
Problem)的推广,即分别以每个顶点作为源顶点并求其至其它顶点的最短距离。更通用的全源最短路径算法包括:
|
||||
|
||||
- 针对稠密图的 Floyd-Warshall 算法:时间复杂度为 O(V3);
|
||||
|
||||
- 针对稀疏图的 Johnson 算法:时间复杂度为 O(V2logV + VE);
|
||||
|
||||
最短路径算法中的最优子结构指的是两顶点之间的最短路径包括路径上其它顶点的最短路径。具体描述为:对于给定的带权图
|
||||
G = (V, E),设 p = \<v1, v2, …,vk\> 是从 v1 到 vk 的最短路径,那么对于任意 i 和
|
||||
j,1 ≤ i ≤ j ≤ k,pij = \<vi, vi+1, …, vj\> 为 p 中顶点 vi 到 vj 的子路径,那么
|
||||
pij 是顶点 vi 到 vj 的最短路径。
|
||||
|
||||

|
||||
|
||||
Floyd-Warshall 算法的设计基于了如下观察。设带权图 G = (V, E) 中的所有顶点 V =
|
||||
{1, 2, . . . , n},考虑一个顶点子集 {1, 2, . . . , k}。对于任意对顶点 i,
|
||||
j,考虑从顶点 i 到 j 的所有路径的中间顶点都来自该子集 {1, 2, . . . , k},设 p
|
||||
是该子集中的最短路径。Floyd-Warshall 算法描述了 p 与 i, j
|
||||
间最短路径及中间顶点集合 {1, 2, . . . , k - 1} 的关系,该关系依赖于 k 是否是路径
|
||||
p 上的一个中间顶点。
|
||||
|
||||

|
||||
|
||||
算法伪码如下:
|
||||
|
||||

|
||||
|
||||
最短路径算法的设计都使用了松弛(relaxation)技术。在算法开始时只知道图中边的权值,然后随着处理逐渐得到各对顶点的最短路径的信息,算法会逐渐更新这些信息,每步都会检查是否可以找到一条路径比当前已有路径更短,这一过程通常称为松弛(relaxation)。
|
||||
|
||||
C\# 代码实现:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 5
|
||||
namespace GraphAlgorithmTesting 6 { 7 class Program 8 { 9 static void
|
||||
Main(string[] args) 10 { 11 int[,] graph = new int[9, 9] 12 { 13 {0, 4, 0, 0, 0,
|
||||
0, 0, 8, 0}, 14 {4, 0, 8, 0, 0, 0, 0, 11, 0}, 15 {0, 8, 0, 7, 0, 4, 0, 0, 2}, 16
|
||||
{0, 0, 7, 0, 9, 14, 0, 0, 0}, 17 {0, 0, 0, 9, 0, 10, 0, 0, 0}, 18 {0, 0, 4, 0,
|
||||
10, 0, 2, 0, 0}, 19 {0, 0, 0, 14, 0, 2, 0, 1, 6}, 20 {8, 11, 0, 0, 0, 0, 1, 0,
|
||||
7}, 21 {0, 0, 2, 0, 0, 0, 6, 7, 0} 22 }; 23 24 Graph g = new
|
||||
Graph(graph.GetLength(0)); 25 for (int i = 0; i \< graph.GetLength(0); i++) 26 {
|
||||
27 for (int j = 0; j \< graph.GetLength(1); j++) 28 { 29 if (graph[i, j] \> 0)
|
||||
30 g.AddEdge(i, j, graph[i, j]); 31 } 32 } 33 34 Console.WriteLine("Graph Vertex
|
||||
Count : {0}", g.VertexCount); 35 Console.WriteLine("Graph Edge Count : {0}",
|
||||
g.EdgeCount); 36 Console.WriteLine(); 37 38 int[,] distSet = g.FloydWarshell();
|
||||
39 PrintSolution(g, distSet); 40 41 // build a directed and negative weighted
|
||||
graph 42 Graph directedGraph1 = new Graph(5); 43 directedGraph1.AddEdge(0, 1,
|
||||
\-1); 44 directedGraph1.AddEdge(0, 2, 4); 45 directedGraph1.AddEdge(1, 2, 3); 46
|
||||
directedGraph1.AddEdge(1, 3, 2); 47 directedGraph1.AddEdge(1, 4, 2); 48
|
||||
directedGraph1.AddEdge(3, 2, 5); 49 directedGraph1.AddEdge(3, 1, 1); 50
|
||||
directedGraph1.AddEdge(4, 3, -3); 51 52 Console.WriteLine(); 53
|
||||
Console.WriteLine("Graph Vertex Count : {0}", directedGraph1.VertexCount); 54
|
||||
Console.WriteLine("Graph Edge Count : {0}", directedGraph1.EdgeCount); 55
|
||||
Console.WriteLine(); 56 57 int[,] distSet1 = directedGraph1.FloydWarshell(); 58
|
||||
PrintSolution(directedGraph1, distSet1); 59 60 // build a directed and positive
|
||||
weighted graph 61 Graph directedGraph2 = new Graph(4); 62
|
||||
directedGraph2.AddEdge(0, 1, 5); 63 directedGraph2.AddEdge(0, 3, 10); 64
|
||||
directedGraph2.AddEdge(1, 2, 3); 65 directedGraph2.AddEdge(2, 3, 1); 66 67
|
||||
Console.WriteLine(); 68 Console.WriteLine("Graph Vertex Count : {0}",
|
||||
directedGraph2.VertexCount); 69 Console.WriteLine("Graph Edge Count : {0}",
|
||||
directedGraph2.EdgeCount); 70 Console.WriteLine(); 71 72 int[,] distSet2 =
|
||||
directedGraph2.FloydWarshell(); 73 PrintSolution(directedGraph2, distSet2); 74
|
||||
75 Console.ReadKey(); 76 } 77 78 private static void PrintSolution(Graph g,
|
||||
int[,] distSet) 79 { 80 Console.Write("\\t"); 81 for (int i = 0; i \<
|
||||
g.VertexCount; i++) 82 { 83 Console.Write(i + "\\t"); 84 } 85
|
||||
Console.WriteLine(); 86 Console.Write("\\t"); 87 for (int i = 0; i \<
|
||||
g.VertexCount; i++) 88 { 89 Console.Write("-" + "\\t"); 90 } 91
|
||||
Console.WriteLine(); 92 for (int i = 0; i \< g.VertexCount; i++) 93 { 94
|
||||
Console.Write(i + "\|\\t"); 95 for (int j = 0; j \< g.VertexCount; j++) 96 { 97
|
||||
if (distSet[i, j] == int.MaxValue) 98 { 99 Console.Write("INF" + "\\t");100 }
|
||||
101 else102 { 103 Console.Write(distSet[i, j] + "\\t");104 } 105 } 106
|
||||
Console.WriteLine(); 107 } 108 } 109 110 class Edge 111 { 112 public Edge(int
|
||||
begin, int end, int weight) 113 { 114 this.Begin = begin;115 this.End = end;116
|
||||
this.Weight = weight;117 } 118 119 public int Begin { get; private set; }120
|
||||
public int End { get; private set; }121 public int Weight { get; private set;
|
||||
}122 123 public override string ToString() 124 { 125 return string.Format(126
|
||||
"Begin[{0}], End[{1}], Weight[{2}]",127 Begin, End, Weight); 128 } 129 } 130 131
|
||||
class Graph 132 { 133 private Dictionary\<int, List\<Edge\>\> \_adjacentEdges134
|
||||
= new Dictionary\<int, List\<Edge\>\>();135 136 public Graph(int vertexCount)
|
||||
137 { 138 this.VertexCount = vertexCount;139 } 140 141 public int VertexCount {
|
||||
get; private set; }142 143 public int EdgeCount 144 { 145 get146 { 147 return
|
||||
\_adjacentEdges.Values.SelectMany(e =\> e).Count(); 148 } 149 } 150 151 public
|
||||
void AddEdge(int begin, int end, int weight) 152 { 153 if
|
||||
(!\_adjacentEdges.ContainsKey(begin)) 154 { 155 var edges = new List\<Edge\>();
|
||||
156 \_adjacentEdges.Add(begin, edges); 157 } 158 159
|
||||
\_adjacentEdges[begin].Add(new Edge(begin, end, weight)); 160 } 161 162 public
|
||||
int[,] FloydWarshell()163 { 164 /\* distSet[,] will be the output matrix that
|
||||
will finally have the shortest165 distances between every pair of vertices
|
||||
\*/166 int[,] distSet = new int[VertexCount, VertexCount];167 168 for (int i =
|
||||
0; i \< VertexCount; i++)169 { 170 for (int j = 0; j \< VertexCount; j++)171 {
|
||||
172 distSet[i, j] = int.MaxValue;173 } 174 } 175 for (int i = 0; i \<
|
||||
VertexCount; i++)176 { 177 distSet[i, i] = 0;178 } 179 180 /\* Initialize the
|
||||
solution matrix same as input graph matrix. Or181 we can say the initial values
|
||||
of shortest distances are based 182 on shortest paths considering no
|
||||
intermediate vertex. \*/183 foreach (var edge in
|
||||
\_adjacentEdges.Values.SelectMany(e =\> e)) 184 { 185 distSet[edge.Begin,
|
||||
edge.End] = edge.Weight; 186 } 187 188 /\* Add all vertices one by one to the
|
||||
set of intermediate vertices.189 ---\> Before start of a iteration, we have
|
||||
shortest distances between all 190 pairs of vertices such that the shortest
|
||||
distances consider only the 191 vertices in set {0, 1, 2, .. k-1} as
|
||||
intermediate vertices. 192 ---\> After the end of a iteration, vertex no. k is
|
||||
added to the set of 193 intermediate vertices and the set becomes {0, 1, 2, ..
|
||||
k} \*/194 for (int k = 0; k \< VertexCount; k++)195 { 196 // Pick all vertices
|
||||
as source one by one197 for (int i = 0; i \< VertexCount; i++)198 { 199 // Pick
|
||||
all vertices as destination for the above picked source200 for (int j = 0; j \<
|
||||
VertexCount; j++)201 { 202 // If vertex k is on the shortest path from203 // i
|
||||
to j, then update the value of distSet[i,j]204 if (distSet[i, k] !=
|
||||
int.MaxValue205 && distSet[k, j] != int.MaxValue206 && distSet[i, k] +
|
||||
distSet[k, j] \< distSet[i, j]) 207 { 208 distSet[i, j] = distSet[i, k] +
|
||||
distSet[k, j]; 209 } 210 } 211 } 212 } 213 214 return distSet; 215 } 216 } 217 }
|
||||
218 }
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
运行结果如下:
|
||||
|
||||

|
||||
168
算法/补充/Kruskal 最小生成树算法.md
Normal file
@@ -0,0 +1,168 @@
|
||||
Kruskal 最小生成树算法
|
||||
|
||||
对于一个给定的连通的无向图 G = (V, E),希望找到一个无回路的子集 T,T 是 E
|
||||
的子集,它连接了所有的顶点,且其权值之和为最小。
|
||||
|
||||

|
||||
|
||||
因为 T 无回路且连接所有的顶点,所以它必然是一棵树,称为生成树(Spanning
|
||||
Tree),因为它生成了图 G。显然,由于树 T 连接了所有的顶点,所以树 T 有 V - 1
|
||||
条边。一张图 G 可以有很多棵生成树,而把确定权值最小的树 T
|
||||
的问题称为**最小生成树问题(Minimum Spanning Tree)**。术语 "最小生成树"
|
||||
实际上是 "最小权值生成树" 的缩写。
|
||||
|
||||
**Kruskal 算法**提供一种在 O(ElogV) 运行时间确定最小生成树的方案。Kruskal
|
||||
算法基于贪心算法(Greedy
|
||||
Algorithm)的思想进行设计,其选择的**贪心策略**就是,每次都选择权重最小的但未形成环路的边加入到生成树中。其算法结构如下:
|
||||
|
||||
1. 将所有的边按照权重非递减排序;
|
||||
|
||||
2. 选择最小权重的边,判断是否其在当前的生成树中形成了一个环路。如果环路没有形成,则将该边加入树中,否则放弃。
|
||||
|
||||
3. 重复步骤 2,直到有 V - 1 条边在生成树中。
|
||||
|
||||
上述步骤 2 中使用了 [Union-Find
|
||||
算法](http://www.cnblogs.com/gaochundong/p/disjoint_set_forests_heuristics.html)来判断是否存在环路。
|
||||
|
||||
例如,下面是一个无向连通图 G。
|
||||
|
||||

|
||||
|
||||
图 G 中包含 9 个顶点和 14 条边,所以期待的最小生成树应包含 (9 - 1) = 8 条边。
|
||||
|
||||
首先对所有的边按照权重的非递减顺序排序:
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
Weight Src Dest 1 7 6 2 8 2 2 6 5 4 0 1 4 2 5 6 8 6 7 2 3 7 7 8 8 0 7 8 1 2 9 3
|
||||
4 10 5 4 11 1 7 14 3 5
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
然后从排序后的列表中选择权重最小的边。
|
||||
|
||||
1\. 选择边 {7, 6},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
2\. 选择边 {8, 2},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
3\. 选择边 {6, 5},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
4\. 选择边 {0, 1},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
5\. 选择边 {2, 5},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
6\. 选择边 {8, 6},有环路形成,放弃。
|
||||
|
||||
7\. 选择边 {2, 3},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
8\. 选择边 {7, 8},有环路形成,放弃。
|
||||
|
||||
9\. 选择边 {0, 7},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
10\. 选择边 {1, 2},有环路形成,放弃。
|
||||
|
||||
11\. 选择边 {3, 4},无环路形成,包含在生成树中。
|
||||
|
||||

|
||||
|
||||
12\. 由于当前生成树中已经包含 V - 1 条边,算法结束。
|
||||
|
||||
C\# 实现的 Kruskal 算法如下。
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 5
|
||||
namespace GraphAlgorithmTesting 6 { 7 class Program 8 { 9 static void
|
||||
Main(string[] args) 10 { 11 Graph g = new Graph(9); 12 g.AddEdge(0, 1, 4); 13
|
||||
g.AddEdge(0, 7, 8); 14 g.AddEdge(1, 2, 8); 15 g.AddEdge(1, 7, 11); 16
|
||||
g.AddEdge(2, 3, 7); 17 g.AddEdge(2, 5, 4); 18 g.AddEdge(8, 2, 2); 19
|
||||
g.AddEdge(3, 4, 9); 20 g.AddEdge(3, 5, 14); 21 g.AddEdge(5, 4, 10); 22
|
||||
g.AddEdge(6, 5, 2); 23 g.AddEdge(8, 6, 6); 24 g.AddEdge(7, 6, 1); 25
|
||||
g.AddEdge(7, 8, 7); 26 27 Console.WriteLine(); 28 Console.WriteLine("Graph
|
||||
Vertex Count : {0}", g.VertexCount); 29 Console.WriteLine("Graph Edge Count :
|
||||
{0}", g.EdgeCount); 30 Console.WriteLine(); 31 32 Console.WriteLine("Is there
|
||||
cycle in graph: {0}", g.HasCycle()); 33 Console.WriteLine(); 34 35 Edge[] mst =
|
||||
g.Kruskal(); 36 Console.WriteLine("MST Edges:"); 37 foreach (var edge in mst) 38
|
||||
{ 39 Console.WriteLine("\\t{0}", edge); 40 } 41 42 Console.ReadKey(); 43 } 44 45
|
||||
class Edge 46 { 47 public Edge(int begin, int end, int weight) 48 { 49
|
||||
this.Begin = begin; 50 this.End = end; 51 this.Weight = weight; 52 } 53 54
|
||||
public int Begin { get; private set; } 55 public int End { get; private set; }
|
||||
56 public int Weight { get; private set; } 57 58 public override string
|
||||
ToString() 59 { 60 return string.Format( 61 "Begin[{0}], End[{1}], Weight[{2}]",
|
||||
62 Begin, End, Weight); 63 } 64 } 65 66 class Subset 67 { 68 public int Parent {
|
||||
get; set; } 69 public int Rank { get; set; } 70 } 71 72 class Graph 73 { 74
|
||||
private Dictionary\<int, List\<Edge\>\> \_adjacentEdges 75 = new
|
||||
Dictionary\<int, List\<Edge\>\>(); 76 77 public Graph(int vertexCount) 78 { 79
|
||||
this.VertexCount = vertexCount; 80 } 81 82 public int VertexCount { get; private
|
||||
set; } 83 84 public IEnumerable\<int\> Vertices { get { return
|
||||
\_adjacentEdges.Keys; } } 85 86 public IEnumerable\<Edge\> Edges 87 { 88 get {
|
||||
return \_adjacentEdges.Values.SelectMany(e =\> e); } 89 } 90 91 public int
|
||||
EdgeCount { get { return this.Edges.Count(); } } 92 93 public void AddEdge(int
|
||||
begin, int end, int weight) 94 { 95 if (!\_adjacentEdges.ContainsKey(begin)) 96
|
||||
{ 97 var edges = new List\<Edge\>(); 98 \_adjacentEdges.Add(begin, edges); 99 }
|
||||
100 101 \_adjacentEdges[begin].Add(new Edge(begin, end, weight)); 102 } 103 104
|
||||
private int Find(Subset[] subsets, int i) 105 { 106 // find root and make root
|
||||
as parent of i (path compression)107 if (subsets[i].Parent != i) 108
|
||||
subsets[i].Parent = Find(subsets, subsets[i].Parent); 109 110 return
|
||||
subsets[i].Parent; 111 } 112 113 private void Union(Subset[] subsets, int x, int
|
||||
y) 114 { 115 int xroot = Find(subsets, x); 116 int yroot = Find(subsets, y); 117
|
||||
118 // Attach smaller rank tree under root of high rank tree119 // (Union by
|
||||
Rank)120 if (subsets[xroot].Rank \< subsets[yroot].Rank) 121
|
||||
subsets[xroot].Parent = yroot; 122 else if (subsets[xroot].Rank \>
|
||||
subsets[yroot].Rank) 123 subsets[yroot].Parent = xroot; 124 125 // If ranks are
|
||||
same, then make one as root and increment126 // its rank by one127 else128 { 129
|
||||
subsets[yroot].Parent = xroot; 130 subsets[xroot].Rank++; 131 } 132 } 133 134
|
||||
public bool HasCycle() 135 { 136 Subset[] subsets = new Subset[VertexCount]; 137
|
||||
for (int i = 0; i \< subsets.Length; i++)138 { 139 subsets[i] = new Subset();
|
||||
140 subsets[i].Parent = i; 141 subsets[i].Rank = 0;142 } 143 144 // Iterate
|
||||
through all edges of graph, find subset of both145 // vertices of every edge, if
|
||||
both subsets are same,146 // then there is cycle in graph.147 foreach (var edge
|
||||
in this.Edges)148 { 149 int x = Find(subsets, edge.Begin); 150 int y =
|
||||
Find(subsets, edge.End); 151 152 if (x == y) 153 { 154 return true;155 } 156 157
|
||||
Union(subsets, x, y); 158 } 159 160 return false;161 } 162 163 public Edge[]
|
||||
Kruskal() 164 { 165 // This will store the resultant MST166 Edge[] mst = new
|
||||
Edge[VertexCount - 1];167 168 // Step 1: Sort all the edges in non-decreasing
|
||||
order of their weight169 // If we are not allowed to change the given graph, we
|
||||
can create a copy of170 // array of edges171 var sortedEdges =
|
||||
this.Edges.OrderBy(t =\> t.Weight);172 var enumerator =
|
||||
sortedEdges.GetEnumerator(); 173 174 // Allocate memory for creating V
|
||||
ssubsets175 // Create V subsets with single elements176 Subset[] subsets = new
|
||||
Subset[VertexCount]; 177 for (int i = 0; i \< subsets.Length; i++)178 { 179
|
||||
subsets[i] = new Subset(); 180 subsets[i].Parent = i; 181 subsets[i].Rank =
|
||||
0;182 } 183 184 // Number of edges to be taken is equal to V-1185 int e = 0;186
|
||||
while (e \< VertexCount - 1)187 { 188 // Step 2: Pick the smallest edge. And
|
||||
increment the index189 // for next iteration190 Edge nextEdge; 191 if
|
||||
(enumerator.MoveNext()) 192 { 193 nextEdge = enumerator.Current; 194 195 int x =
|
||||
Find(subsets, nextEdge.Begin); 196 int y = Find(subsets, nextEdge.End); 197 198
|
||||
// If including this edge does't cause cycle, include it199 // in result and
|
||||
increment the index of result for next edge200 if (x != y) 201 { 202 mst[e++] =
|
||||
nextEdge; 203 Union(subsets, x, y); 204 } 205 else206 { 207 // Else discard the
|
||||
nextEdge208 } 209 } 210 } 211 212 return mst; 213 } 214 } 215 } 216 }
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
输出结果如下:
|
||||
|
||||

|
||||
119
算法/补充/Prim 最小生成树算法.md
Normal file
@@ -0,0 +1,119 @@
|
||||
Prim 最小生成树算法
|
||||
|
||||
**Prim 算法**是一种解决**最小生成树问题(Minimum Spanning Tree)**的算法。和
|
||||
[Kruskal
|
||||
算法](http://www.cnblogs.com/gaochundong/p/kruskal_minimum_spanning_tree.html)类似,Prim
|
||||
算法的设计也是基于贪心算法(Greedy algorithm)。
|
||||
|
||||
Prim
|
||||
算法的思想很简单,一棵生成树必须连接所有的顶点,而要保持最小权重则每次选择邻接的边时要选择较小权重的边。Prim
|
||||
算法看起来非常类似于单源最短路径 [Dijkstra
|
||||
算法](http://www.cnblogs.com/gaochundong/p/dijkstra_algorithm.html),从源点出发,寻找当前的最短路径,每次比较当前可达邻接顶点中最小的一个边加入到生成树中。
|
||||
|
||||
例如,下面这张连通的无向图 G,包含 9 个顶点和 14
|
||||
条边,所以期待的最小生成树应包含 (9 - 1) = 8 条边。
|
||||
|
||||

|
||||
|
||||
创建 mstSet 包含到所有顶点的距离,初始为 INF,源点 0 的距离为 0,{0, INF, INF,
|
||||
INF, INF, INF, INF, INF, INF}。
|
||||
|
||||
选择当前最短距离的顶点,即还是顶点 0,将 0 加入 MST,此时邻接顶点为 1 和 7。
|
||||
|
||||

|
||||
|
||||
选择当前最小距离的顶点 1,将 1 加入 MST,此时邻接顶点为 2。
|
||||
|
||||

|
||||
|
||||
选择 2 和 7 中最小距离的顶点为 7,将 7 加入 MST,此时邻接顶点为 6 和 8。
|
||||
|
||||

|
||||
|
||||
选择 2, 6, 8 中最小距离的顶点为 6,将 6 加入 MST,此时邻接顶点为 5。
|
||||
|
||||

|
||||
|
||||
重复上面步骤直到遍历完所有顶点为止,会得到如下 MST。
|
||||
|
||||

|
||||
|
||||
C\# 实现 **Prim 算法**如下。Prim 算法可以达到 O(ElogV)
|
||||
的运行时间,如果采用斐波那契堆实现,运行时间可以减少到 O(E + VlogV),如果 V
|
||||
远小于 E 的话,将是对算法较大的改进。
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 5
|
||||
namespace GraphAlgorithmTesting 6 { 7 class Program 8 { 9 static void
|
||||
Main(string[] args) 10 { 11 Graph g = new Graph(9); 12 g.AddEdge(0, 1, 4); 13
|
||||
g.AddEdge(0, 7, 8); 14 g.AddEdge(1, 2, 8); 15 g.AddEdge(1, 7, 11); 16
|
||||
g.AddEdge(2, 3, 7); 17 g.AddEdge(2, 5, 4); 18 g.AddEdge(3, 4, 9); 19
|
||||
g.AddEdge(3, 5, 14); 20 g.AddEdge(5, 4, 10); 21 g.AddEdge(6, 5, 2); 22
|
||||
g.AddEdge(7, 6, 1); 23 g.AddEdge(7, 8, 7); 24 g.AddEdge(8, 2, 2); 25
|
||||
g.AddEdge(8, 6, 6); 26 27 // sorry, this is an undirect graph, 28 // so, you
|
||||
know that this is not a good idea. 29 List\<Edge\> edges = g.Edges 30 .Select(e
|
||||
=\> new Edge(e.End, e.Begin, e.Weight)) 31 .ToList(); 32 foreach (var edge in
|
||||
edges) 33 { 34 g.AddEdge(edge.Begin, edge.End, edge.Weight); 35 } 36 37
|
||||
Console.WriteLine(); 38 Console.WriteLine("Graph Vertex Count : {0}",
|
||||
g.VertexCount); 39 Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount); 40
|
||||
Console.WriteLine(); 41 42 List\<Edge\> mst = g.Prim(); 43
|
||||
Console.WriteLine("MST Edges:"); 44 foreach (var edge in mst.OrderBy(e =\>
|
||||
e.Weight)) 45 { 46 Console.WriteLine("\\t{0}", edge); 47 } 48 49
|
||||
Console.ReadKey(); 50 } 51 52 class Edge 53 { 54 public Edge(int begin, int end,
|
||||
int weight) 55 { 56 this.Begin = begin; 57 this.End = end; 58 this.Weight =
|
||||
weight; 59 } 60 61 public int Begin { get; private set; } 62 public int End {
|
||||
get; private set; } 63 public int Weight { get; private set; } 64 65 public
|
||||
override string ToString() 66 { 67 return string.Format( 68 "Begin[{0}],
|
||||
End[{1}], Weight[{2}]", 69 Begin, End, Weight); 70 } 71 } 72 73 class Graph 74 {
|
||||
75 private Dictionary\<int, List\<Edge\>\> \_adjacentEdges 76 = new
|
||||
Dictionary\<int, List\<Edge\>\>(); 77 78 public Graph(int vertexCount) 79 { 80
|
||||
this.VertexCount = vertexCount; 81 } 82 83 public int VertexCount { get; private
|
||||
set; } 84 85 public IEnumerable\<int\> Vertices { get { return
|
||||
\_adjacentEdges.Keys; } } 86 87 public IEnumerable\<Edge\> Edges 88 { 89 get {
|
||||
return \_adjacentEdges.Values.SelectMany(e =\> e); } 90 } 91 92 public int
|
||||
EdgeCount { get { return this.Edges.Count(); } } 93 94 public void AddEdge(int
|
||||
begin, int end, int weight) 95 { 96 if (!\_adjacentEdges.ContainsKey(begin)) 97
|
||||
{ 98 var edges = new List\<Edge\>(); 99 \_adjacentEdges.Add(begin, edges); 100 }
|
||||
101 102 \_adjacentEdges[begin].Add(new Edge(begin, end, weight)); 103 } 104 105
|
||||
public List\<Edge\> Prim() 106 { 107 // Array to store constructed MST108 int[]
|
||||
parent = new int[VertexCount];109 110 // Key values used to pick minimum weight
|
||||
edge in cut111 int[] keySet = new int[VertexCount];112 113 // To represent set
|
||||
of vertices not yet included in MST114 bool[] mstSet = new bool[VertexCount];115
|
||||
116 // Initialize all keys as INFINITE117 for (int i = 0; i \< VertexCount;
|
||||
i++)118 { 119 keySet[i] = int.MaxValue;120 mstSet[i] = false;121 } 122 123 //
|
||||
Always include first 1st vertex in MST.124 // Make key 0 so that this vertex is
|
||||
picked as first vertex125 keySet[0] = 0;126 parent[0] = -1; // First node is
|
||||
always root of MST127 128 // The MST will have V vertices129 for (int i = 0; i
|
||||
\< VertexCount - 1; i++)130 { 131 // Pick thd minimum key vertex from the set of
|
||||
vertices132 // not yet included in MST133 int u = CalculateMinDistance(keySet,
|
||||
mstSet); 134 135 // Add the picked vertex to the MST Set136 mstSet[u] = true;137
|
||||
138 // Update key value and parent index of the adjacent vertices of139 // the
|
||||
picked vertex. Consider only those vertices which are not yet140 // included in
|
||||
MST141 for (int v = 0; v \< VertexCount; v++)142 { 143 // graph[u, v] is non
|
||||
zero only for adjacent vertices of m144 // mstSet[v] is false for vertices not
|
||||
yet included in MST145 // Update the key only if graph[u, v] is smaller than
|
||||
key[v]146 if (!mstSet[v] 147 && \_adjacentEdges.ContainsKey(u) 148 &&
|
||||
\_adjacentEdges[u].Exists(e =\> e.End == v)) 149 { 150 int d =
|
||||
\_adjacentEdges[u].Single(e =\> e.End == v).Weight; 151 if (d \< keySet[v]) 152
|
||||
{ 153 keySet[v] = d; 154 parent[v] = u; 155 } 156 } 157 } 158 } 159 160 // get
|
||||
all MST edges161 List\<Edge\> mst = new List\<Edge\>(); 162 for (int i = 1; i \<
|
||||
VertexCount; i++)163 mst.Add(\_adjacentEdges[parent[i]].Single(e =\> e.End ==
|
||||
i)); 164 165 return mst; 166 } 167 168 private int CalculateMinDistance(int[]
|
||||
keySet, bool[] mstSet)169 { 170 int minDistance = int.MaxValue;171 int
|
||||
minDistanceIndex = -1;172 173 for (int v = 0; v \< VertexCount; v++)174 { 175 if
|
||||
(!mstSet[v] && keySet[v] \<= minDistance) 176 { 177 minDistance = keySet[v]; 178
|
||||
minDistanceIndex = v; 179 } 180 } 181 182 return minDistanceIndex; 183 } 184 }
|
||||
185 } 186 }
|
||||
|
||||

|
||||
|
||||
复制代码
|
||||
|
||||
输出结果如下:
|
||||
|
||||

|
||||
|
||||
**参考资料**
|
||||
22
算法/补充/P问题、NP问题和NPC问题.md
Normal file
@@ -0,0 +1,22 @@
|
||||
时间复杂度
|
||||
|
||||
时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当问题规模扩大后,程序需要的时间长度增长得有多快。也就是说,对于高速处理数据的计算机来说,处理某一个特定数据的效率不能衡量一个程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。不管数据有多大,程序处理花的时间始终是那么多的,我们就说这个程序很好,具有O(1)的时间复杂度,也称常数级复杂度;数据规模变得有多大,花的时间也跟着变得有多长,这个程序的时间复杂度就是O(n),比如找n个数中的最大值;而像冒泡排序、插入排序等,数据扩大2倍,时间变慢4倍的,属于O(n\^2)的复杂度。还有一些穷举类的算法,所需时间长度成几何阶数上涨,这就是O(a\^n)的指数级复杂度,甚至O(n!)的阶乘级复杂度。不会存在O(2\*n\^2)的复杂度,因为前面的那个“2”是系数,根本不会影响到整个程序的时间增长。同样地,O
|
||||
(n\^3+n\^2)的复杂度也就是O(n\^3)的复杂度。因此,我们会说,一个O(0.01\*n\^3)的程序的效率比O(100\*n\^2)的效率低,尽管在n很小的时候,前者优于后者,但后者时间随数据规模增长得慢,最终O(n\^3)的复杂度将远远超过O(n\^2)。我们也说,O(n\^100)的复杂度小于O(1.01\^n)的复杂度。
|
||||
|
||||
容易看出,前面的几类复杂度被分为两种级别,其中后者的复杂度无论如何都远远大于前者:一种是O(1),O(log(n)),O(n\^a)等,我们把它叫做多项式级的复杂度,因为它的规模n出现在底数的位置;另一种是O(a\^n)和O(n!)型复杂度,它是非多项式级的,其复杂度计算机往往不能承受。当我们在解决一个问题时,我们选择的算法通常都需要是多项式级的复杂度,非多项式级的复杂度需要的时间太多,往往会超时,除非是数据规模非常小。
|
||||
|
||||
P类问题的概念
|
||||
|
||||
如果一个问题可以找到一个能在多项式的时间里解决它的算法,那么这个问题就属于P问题。
|
||||
|
||||
NP问题的概念
|
||||
|
||||
这个就有点难理解了,或者说容易理解错误。在这里强调(回到我竭力想澄清的误区上),NP问题不是非P类问题。NP问题是指可以在多项式的时间里验证一个解的问题。NP问题的另一个定义是,可以在多项式的时间里猜出一个解的问题。比方说,我RP很好,在程序中需要枚举时,我可以一猜一个准。现在某人拿到了一个求最短路径的问题,问从起点到终点是否有一条小于100个单位长度的路线。它根据数据画好了图,但怎么也算不出来,于是来问我:你看怎么选条路走得最少?我说,我RP很好,肯定能随便给你指条很短的路出来。然后我就胡乱画了几条线,说就这条吧。那人按我指的这条把权值加起来一看,嘿,神了,路径长度98,比100小。于是答案出来了,存在比100小的路径。别人会问他这题怎么做出来的,他就可以说,因为我找到了一个比100
|
||||
小的解。在这个题中,找一个解很困难,但验证一个解很容易。验证一个解只需要O(n)的时间复杂度,也就是说我可以花O(n)的时间把我猜的路径的长度加出来。那么,只要我RP好,猜得准,我一定能在多项式的时间里解决这个问题。我猜到的方案总是最优的,不满足题意的方案也不会来骗我去选它。这就是NP问题。当然有不是NP问题的问题,即你猜到了解但是没用,因为你不能在多项式的时间里去验证它。下面我要举的例子是一个经典的例子,它指出了一个目前还没有办法在多项式的时间里验证一个解的问题。很显然,前面所说的Hamilton回路是NP问题,因为验证一条路是否恰好经过了每一个顶点非常容易。但我要把问题换成这样:试问一个图中是否不存在Hamilton回路。这样问题就没法在多项式的时间里进行验证了,因为除非你试过所有的路,否则你不敢断定它“没有Hamilton回路”。
|
||||
|
||||
之所以要定义NP问题,是因为通常只有NP问题才可能找到多项式的算法。我们不会指望一个连多项式地验证一个解都不行的问题存在一个解决它的多项式级的算法。相信读者很快明白,信息学中的号称最困难的问题——“NP问题”,实际上是在探讨NP问题与P类问题的关系。
|
||||
|
||||
NPC问题的定义
|
||||
|
||||
同时满足下面两个条件的问题就是NPC问题。首先,它得是一个NP问题;然后,所有的NP问题都可以约化到它。证明一个问题是
|
||||
NPC问题也很简单。先证明它至少是一个NP问题,再证明其中一个已知的NPC问题能约化到它(由约化的传递性,则NPC问题定义的第二条也得以满足;至于第一个NPC问题是怎么来的,下文将介绍),这样就可以说它是NPC问题了。
|
||||
13
算法/补充/TSP旅行商问题.md
Normal file
@@ -0,0 +1,13 @@
|
||||
问题分析
|
||||
|
||||
有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路已保证其旅行的费用最少?
|
||||
|
||||

|
||||
|
||||
贪心算法
|
||||
|
||||
动态规划算法
|
||||
|
||||
分支限界算法
|
||||
|
||||
遗传算法
|
||||
BIN
算法/补充/media/028d88e6512c431a0680a0571d7a5675.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
算法/补充/media/0c06f40a0719bebffc78d45c50d62e87.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
算法/补充/media/0f264c0a5bbd1a01e78bda2fe8ab7db3.jpeg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
算法/补充/media/0fc9c39db519692eb9568c5aca664304.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
算法/补充/media/1163371b1fee9f8427fd967986a18f51.jpeg
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
算法/补充/media/14d56ddfaf928586b3fb2cfdbbd5ec94.jpeg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
算法/补充/media/160a163baff4ec1652cb64f7ff6a8577.jpeg
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
算法/补充/media/20e94f670319849e1209cbe28e9ec5fe.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
算法/补充/media/3206e454a556f7a6f021c384858fea1c.jpeg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
算法/补充/media/3e038dcf92495e474695b88e9fd3fde4.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
算法/补充/media/3f6982193bf382027415cc1b54adaa97.gif
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
算法/补充/media/44af8a5f1fc67d503c2ffa1f75c39f9c.jpeg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
算法/补充/media/45f694182b0df6b3ff26904265f1d5ac.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
算法/补充/media/48554fff118a3129374906e0a905d876.jpeg
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
算法/补充/media/5098aea20c34b2944158e6b0622954ff.jpeg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
算法/补充/media/51e409b11aa51c150090697429a953ed.gif
Normal file
|
After Width: | Height: | Size: 263 B |
BIN
算法/补充/media/55e7000759c9f607cef012b78f7f8f09.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
算法/补充/media/6b2a27583131a012247ddb212cddcf8b.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
算法/补充/media/72b66188c7153bdaaeb94504bf6c8c65.jpeg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
算法/补充/media/7909dda678c34ea139bf725689e58761.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
算法/补充/media/804412a0012e45a685217d5fd579fe61.jpeg
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
算法/补充/media/9e5e619c58d10df405b618a18101fb78.jpeg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
算法/补充/media/9fd60a2c349a5f3382a3ac71344da53d.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
算法/补充/media/a2a1f6233a2219cf362ac66675e74c89.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
算法/补充/media/a3460bbcc926be103e406d581ac4612a.jpeg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
算法/补充/media/a623e7938bac06d833a52b042d1936a5.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
算法/补充/media/a69a98f4ac53d314d8fcfc0aa5fd005e.jpeg
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
算法/补充/media/bc10e6800b78eac0fb9893134db87cca.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
算法/补充/media/bddb24235aaf81ea66da626756cdfb48.jpeg
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
算法/补充/media/c0fd7c31e5058884c3d218930d076182.jpeg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
算法/补充/media/ce1292f05670437ae4832b649bde8b8e.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
算法/补充/media/da34421ea01b4c263b5bba06e67b4c39.gif
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
算法/补充/media/da54c513dbc3845d6ba4009044bb16b7.jpeg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
算法/补充/media/e6bcbe8540508ae02a25725926ef375a.jpeg
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
算法/补充/media/e94c6e5fc490453f5a2d31e744227bcc.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
算法/补充/media/e95406c1bb140d86030be10b448f868f.jpeg
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
算法/补充/media/f35f5beffbc44b89085a6241d5ba154e.jpeg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
算法/补充/media/f8d48508d06e4d604fbccd69b9c5eccf.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
算法/补充/media/fa780b4a0df60501e6842a03fc6672f9.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
273
算法/补充/遗传算法详解.md
Normal file
@@ -0,0 +1,273 @@
|
||||
遗传算法定义
|
||||
|
||||
遗传算法(Genetic Algorithm,
|
||||
GA)起源于对生物系统所进行的计算机模拟研究。它是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法,借鉴了达尔文的进化论和孟德尔的遗传学说。其本质是一种高效、并行、全局搜索的方法,能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应地控制搜索过程以求得最佳解。
|
||||
|
||||
袋鼠跳问题(纯粹是觉得有意思)
|
||||
|
||||
**“袋鼠跳”问题**
|
||||
|
||||
既然我们把函数曲线理解成一个一个山峰和山谷组成的山脉。那么我们可以设想所得到的每一个解就是一只袋鼠,我们希望它们不断的向着更高处跳去,直到跳到最高的山峰(尽管袋鼠本身不见得愿意那么做)。所以求最大值的过程就转化成一个“袋鼠跳”的过程。
|
||||
|
||||
作为对比下面简单介绍“袋鼠跳”的几种方式。
|
||||
|
||||
1\. 爬山法(最速上升爬山法):
|
||||
|
||||
从搜索空间中随机产生邻近的点,从中选择对应解最优的个体,替换原来的个体,不断重复上述过程。因为爬山法只对“邻近”的点作比较,所以目光比较“短浅”,常常只能收敛到离开初始位置比较近的局部最优解上面。对于存在很多局部最优点的问题,通过一个简单的迭代找出全局最优解的机会非常渺茫。(在爬山法中,袋鼠最有希望到达最靠近它出发点的山顶,但不能保证该山顶是珠穆朗玛峰,或者是一个非常高的山峰。因为一路上它只顾上坡,没有下坡。)
|
||||
|
||||
2\. 模拟退火:
|
||||
|
||||
这个方法来自金属热加工过程的启发。在金属热加工过程中,当金属的温度超过它的熔点(Melting
|
||||
Point)时,原子就会激烈地随机运动。与所有的其它的物理系统相类似,原子的这种运动趋向于寻找其能量的极小状态。在这个能量的变迁过程中,开始时,温度非常高,
|
||||
使得原子具有很高的能量。随着温度不断降低,金属逐渐冷却,金属中的原子的能量就越来越小,最后达到所有可能的最低点。利用模拟退火的时候,让算法从较大的跳跃开始,使到它有足够的“能量”逃离可能“路过”的局部最优解而不至于限制在其中,当它停在全局最优解附近的时候,逐渐的减小跳跃量,以便使其“落脚
|
||||
”到全局最优解上。(在模拟退火中,袋鼠喝醉了,而且随机地大跳跃了很长时间。运气好的话,它从一个山峰跳过山谷,到了另外一个更高的山峰上。但最后,它渐渐清醒了并朝着它所在的峰顶跳去。)
|
||||
|
||||
3\. 遗传算法:
|
||||
|
||||
模拟物竞天择的生物进化过程,通过维护一个潜在解的群体执行了多方向的搜索,并支持这些方向上的信息构成和交换。是以面为单位的搜索,比以点为单位的搜索,更能发现全局最优解。(在遗传算法中,有很多袋鼠,它们降落到喜玛拉雅山脉的任意地方。**这些袋鼠并不知道它们的任务是寻找珠穆朗玛峰。**但每过几年,就在一些海拔高度较低的地方射杀一些袋鼠,并希望存活下来的袋鼠是多产的,在它们所处的地方生儿育女*。*)(或者换个说法。从前,有一大群袋鼠,它们被莫名其妙的零散地遗弃于喜马拉雅山脉。于是只好在那里艰苦的生活。海拔低的地方弥漫着一种无色无味的毒气,海拔越高毒气越稀薄。可是可怜的袋鼠们对此**全然不觉**,还是习惯于活蹦乱跳。于是,不断有袋鼠死于海拔较低的地方,而越是在海拔高的袋鼠越是能活得更久,也越有机会生儿育女。就这样经过许多年,这些袋鼠们竟然都不自觉地聚拢到了一个个的山峰上,可是在所有的袋鼠中,只有聚拢到珠穆朗玛峰的袋鼠被带回了美丽的澳洲。)
|
||||
|
||||
相关术语
|
||||
|
||||
**基因型(genotype)**
|
||||
|
||||
性状染色体的内部表现;
|
||||
|
||||
**表现型(phenotype)**
|
||||
|
||||
染色体决定的性状的外部表现,或者说,根据基因型形成的个体的外部表现;
|
||||
|
||||
**进化(evolution)**
|
||||
|
||||
种群逐渐适应生存环境,品质不断得到改良。生物的进化是以种群的形式进行的。
|
||||
|
||||
**适应度(fitness)**
|
||||
|
||||
度量某个物种对于生存环境的适应程度。
|
||||
|
||||
**选择(selection)**
|
||||
|
||||
> 以一定的概率从种群中选择若干个个体。一般,选择过程是一种基于适应度的优胜劣汰的过程。
|
||||
|
||||
**复制(reproduction)**
|
||||
|
||||
> 细胞分裂时,遗传物质DNA通过复制而转移到新产生的细胞中,新细胞就继承了旧细胞的基因。
|
||||
|
||||
**交叉(crossover)**
|
||||
|
||||
> 两个染色体的某一相同位置处DNA被切断,前后两串分别交叉组合形成两个新的染色体。也称基因重组或杂交;
|
||||
|
||||
**变异(mutation)**
|
||||
|
||||
复制时可能(很小的概率)产生某些复制差错,变异产生新的染色体,表现出新的性状。
|
||||
|
||||
**编码(coding)**
|
||||
|
||||
> DNA中遗传信息在一个长链上按一定的模式排列。遗传编码可看作从表现型到基因型的映射。
|
||||
|
||||
**解码(decoding)**
|
||||
|
||||
基因型到表现型的映射。
|
||||
|
||||
**个体(individual)**
|
||||
|
||||
指染色体带有特征的实体;
|
||||
|
||||
**种群(population)**
|
||||
|
||||
个体的集合,该集合内个体数称为种群的大小。
|
||||
|
||||
基础定义
|
||||
|
||||
Ø**染色体与基因**
|
||||
|
||||
染色体(chromosome)就是问题中个体的某种字符串形式的编码表示。字符串中的字符也就称为基因(gene)。
|
||||
|
||||
Ø**个体**
|
||||
|
||||
个体就是模拟生物个体而对问题中的对象(一般就是问题的解)的一种称呼,一个个体也就是搜索空间中的一个点。
|
||||
|
||||
Ø**种群**
|
||||
|
||||
种群(population)就是模拟生物种群而由若干个体组成的群体,
|
||||
它一般是整个搜索空间的一个很小的子集。
|
||||
|
||||
Ø**适应度与适应度函数**
|
||||
|
||||
适应度(fitness)就是借鉴生物个体对环境适应程度,而对问题中的个体对象所设计的表征其优劣的一种测度。适应度函数(fitness
|
||||
function)就是问题中的全体个体与其适应度之间的一个对应关系。它一般是一个实值函数。该函数就是遗传算法中指导搜索的评价函数。
|
||||
|
||||
Ø**遗传操作**
|
||||
|
||||
亦称遗传算子(genetic operator),就是关于染色体的运算。遗传算法中有三种遗传操作:
|
||||
|
||||
● 选择-复制(selection-reproduction)
|
||||
|
||||
● 交叉(crossover,亦称交换、交配
|
||||
|
||||
● 变异(mutation,亦称突变)
|
||||
|
||||
遗传算子
|
||||
|
||||
**● 选择-复制(selection-reproduction)**
|
||||
|
||||
通常做法是:对于一个规模为N的种群S,按每个染色体xi∈S的选择概率P(xi)所决定的选中机会,
|
||||
分N次从S中随机选定N个染色体, 并进行复制。
|
||||
|
||||

|
||||
|
||||
上述公式中,f(xi)表示个体的适应度函数,xi表示个体,p(xi)表示选择概率。
|
||||
|
||||
**● 交叉(crossover,亦称交换、交配或杂交)**
|
||||
|
||||
互换两个染色体某些位上的基因。
|
||||
|
||||
例如, 设染色体 s1=01001011, s2=10010101, 交换其后4位基因, 即s1′=01000101,
|
||||
s2′=10011011可以看做是原染色体s1和s2的子代染色体。
|
||||
|
||||

|
||||
|
||||
**● 变异(mutation,亦称突变)**
|
||||
|
||||
就是改变染色体某个(些)位上的基因。
|
||||
|
||||
例如, 设染色体 s=11001101将其第三位上的0变为1, 即s=11001101 →11101101=
|
||||
s′。s′也可以看做是原染色体s的子代染色体。
|
||||
|
||||

|
||||
|
||||
**● 相关算法**
|
||||
|
||||
**选择-复制中的赌轮算法**
|
||||
|
||||

|
||||
|
||||
**交叉中的PMX部分匹配法**
|
||||
|
||||
PMX操作是Goldberg和Lingle于1985年提出的,在PMX操作中先随机产生两个位串交叉点,定义这两点之间的区域为一匹配交叉区域,并使用位置交换操作来交换两个父串的匹配区域。考虑下面一个实例,如两父及匹配区域为:
|
||||
|
||||
A=9 8 5 \| 4 6 7 \| 1 3 2 0
|
||||
|
||||
B=8 6 3 \| 2 0 1 \| 9 5 4 7
|
||||
|
||||
首先交换A和B的两个匹配区域,得到:
|
||||
|
||||
A’=9 8 5 \| 2 0 1 \| 1 3 2 0
|
||||
|
||||
B’=8 6 3 \| 4 6 7 \| 9 5 4 7
|
||||
|
||||
对于A’、B’两子串中匹配区域以外出现的遍历重复,依据匹配区域内的位置映射关系,逐一进行交换,对于A’有2到4,0到6,1到7的位置符号映射,对于A’的匹配区域以外的2,0,1分别以4,6,7替换,则得:
|
||||
|
||||
A’’=9 8 5 \| 2 0 1 \| 7 3 4 6
|
||||
|
||||
同理可得:
|
||||
|
||||
B’’=8 0 3 \| 4 6 7 \| 9 5 2 1
|
||||
|
||||
这样,每个子串的次序由其父串部分地确定。
|
||||
|
||||
**交叉中的OX顺序交叉法**
|
||||
|
||||
1985年Davis等人提出了基于路径表示的顺序交叉(OX)操作,OX操作能够保留排列,并融合不同排列的有序结构单元。此方法开始也是选择一个匹配区域:
|
||||
|
||||
A=9 8 5 \| 4 6 7 \| 1 3 2 0
|
||||
|
||||
B=8 6 3 \| 2 0 1 \| 9 5 4 7
|
||||
|
||||
首先,两个交叉点之间的中间段保持不变,在其区域外的相应位置标记X,得到
|
||||
|
||||
A’=X X X \| 4 6 7 \| X X X X
|
||||
|
||||
B’=X X X \| 2 0 1 \| X X X X
|
||||
|
||||
其次,记录父个体B从第二个交叉点开始城市码的排列顺序,当到达表尾时,返回表头继续记录城市码,直至到达第二个交叉点结束,这样便获得了父个体B从第二个交叉点开始的城市码排列顺序为9-5-4-7-8-6-3-2-0-1,对于父个体A而言,已有城市码4,6,7将它们从父个体B的城市码排列顺序中去掉,得到排列顺序9-5-8-3-2-0-1,再将这个排列顺序复制给父个体A,复制的起点也是从第二个交叉点开始,以此决定子个体1对应位置的未知码X,这样新个体A’’为:
|
||||
|
||||
A’’=2 0 1 4 6 7 9 5 8 3
|
||||
|
||||
同样,利用同样的方法可以得到交叉后的B’’染色体为:
|
||||
|
||||
B’’=4 6 7 2 0 1 3 9 8 5
|
||||
|
||||
算法步骤
|
||||
|
||||
**遗传算法的基本流程图**
|
||||
|
||||

|
||||
|
||||
**遗传算法步骤用文字描述如下:**
|
||||
|
||||
> a)在搜索空间U上定义一个适应度函数f(x),给定种群规模N,交叉率Pc和变异率Pm,代数T;
|
||||
|
||||
> b)随机产生U中的N个个体s1, s2, …, sN,组成初始种群S={s1, s2, …,
|
||||
> sN},置代数计数器t=1;
|
||||
|
||||
> c)计算S中每个个体的适应度f() ;
|
||||
|
||||
> d)若终止条件满足,则取S中适应度最大的个体作为所求结果,算法结束。
|
||||
|
||||
> e)按选择概率P(xi)所决定的选中机会,每次从S中随机选定1个个体并将其染色体复制,共做N次,然后将复制所得的N个染色体组成群体S1;
|
||||
|
||||
> f)按交叉率Pc所决定的参加交叉的染色体数c,从S1中随机确定c个染色体,配对进行交叉操作,并用产生的新染色体代替原染色体,得群体S2;
|
||||
|
||||
> g)按变异率Pm所决定的变异次数m,从S2中随机确定m个染色体,分别进行变异操作,并用产生的新染色体代替原染色体,得群体S3;
|
||||
|
||||
> h)将群体S3作为新一代种群,即用S3代替S,t = t+1,转步3;
|
||||
|
||||
**遗传算法步骤用代码描述如下:**
|
||||
|
||||
> 1\. initiate(); //产生初始化种群
|
||||
|
||||
> 2\. evaluation( 0 ); //对初始化种群进行评估、排序
|
||||
|
||||
> 3\. for( i = 0 ; i \< MAXloop ; i++ )
|
||||
|
||||
> 4\. {
|
||||
|
||||
> 5\. cross(); //进行交叉操作
|
||||
|
||||
> 6\. evaluation(); //对子种群进行评估、排序
|
||||
|
||||
> 7\. selection(); //对父子种群中选择最优的NUM个作为新的父种群
|
||||
|
||||
> 8\. if( record() = = 1 ) //满足终止规则1,则flag=1并停止循环
|
||||
|
||||
> 9\. {
|
||||
|
||||
> 10\. break;
|
||||
|
||||
> 11\. }
|
||||
|
||||
> 12\. mutation(); //变异操作
|
||||
|
||||
> 13\. }
|
||||
|
||||
**遗传算法中的控制参数**
|
||||
|
||||
> Ø种群规模;
|
||||
|
||||
> Ø最大换代数;
|
||||
|
||||
> Ø交叉率(crossover
|
||||
> rate)就是参加交叉运算的染色体个数占全体染色体总数的比例,记为Pc,取值范围一般为0.4~0.99;
|
||||
|
||||
> Ø变异率(mutation
|
||||
> rate)是指发生变异的基因位数所占全体染色体的基因总位数的比例,记为Pm,取值范围一般为0.0001~0.1。
|
||||
|
||||
其他思想
|
||||
|
||||
**精英主义**
|
||||
|
||||
当利用交叉和变异产生新的一代时,我们有很大的可能把在某个中间步骤中得到的最优解丢失。
|
||||
|
||||
精英主义的思想是,在每一次产生新的一代时,首先把当前最优解原封不动的复制到新的一代中。然后按照前面所说的那样做就行。精英主义方法可以大幅提高运算速度,因为它可以防止丢失掉找到的最好的解。
|
||||
|
||||
精英主义是基本遗传算法的一种优化。为了防止进化过程中产生的最优解被交叉和变异所破坏,可以将每一代中的最优解原封不动的复制到下一代中。
|
||||
|
||||
**灾变主义**
|
||||
|
||||
遗传算法的局部搜索能力较强,但是很容易陷入局部极值。引用网上的一段原话:
|
||||
|
||||
“那么如何解决遗传算法容易陷入局部极值的问题呢?让我们来看看大自然提供的方案。六千五百万年以前,恐龙和灵长类动物并存,恐龙在地球上占绝对统治地位,如果恐龙没有灭绝灵长类动物是绝没有可能统治地球的。正是恐龙的灭绝才使灵长类动物有了充分进化的余地,事实上地球至少经历了5次物种大灭绝,每次物种灭绝都给更加高级的生物提供了充分进化的余地。所以要跳出局部极值就必须杀死当前所有的优秀个体,从而让远离当前极值的点有充分的进化余地。这就是灾变的思想。”
|
||||
|
||||
灾变就是杀掉最优秀的个体,这样才可能产生更优秀的物种。那何时进行灾变,灾变次数又如何设定?
|
||||
|
||||
何时进行灾变,可以采用灾变倒计数的方式。如果n代还没有出现比之前更优秀的个体时,可以发生灾变。灾变次数可以这样来确定,如果若干次灾变后产生的个体的适应度与没灾变前的一样,可停止灾变。
|
||||