blog/assets/js/fcc91f97.9c27af9a.js
github-actions[bot] 70bdf5ed11 deploy: d91860e0f7
2023-09-07 18:30:53 +00:00

1 line
No EOL
15 KiB
JavaScript

"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[6234],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>d});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function o(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var m=n.createContext({}),l=function(e){var t=n.useContext(m),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},p=function(e){var t=l(e.components);return n.createElement(m.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,m=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=l(a),u=r,d=c["".concat(m,".").concat(u)]||c[u]||h[u]||i;return a?n.createElement(d,s(s({ref:t},p),{},{components:a})):n.createElement(d,s({ref:t},p))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,s=new Array(i);s[0]=u;var o={};for(var m in t)hasOwnProperty.call(t,m)&&(o[m]=t[m]);o.originalType=e,o[c]="string"==typeof e?e:r,s[1]=o;for(var l=2;l<i;l++)s[l]=a[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,a)}u.displayName="MDXCreateElement"},4507:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>o,toc:()=>l});var n=a(7462),r=(a(7294),a(3905));const i={id:"iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",tags:["csharp","graphs","iterators","iterative"],last_update:{date:new Date("2021-05-18T00:00:00.000Z")}},s=void 0,o={unversionedId:"graphs/iterative-and-iterators",id:"graphs/iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",source:"@site/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",sourceDirName:"10-graphs",slug:"/graphs/iterative-and-iterators",permalink:"/ib002/graphs/iterative-and-iterators",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",tags:[{label:"csharp",permalink:"/ib002/tags/csharp"},{label:"graphs",permalink:"/ib002/tags/graphs"},{label:"iterators",permalink:"/ib002/tags/iterators"},{label:"iterative",permalink:"/ib002/tags/iterative"}],version:"current",lastUpdatedAt:1621296e3,formattedLastUpdatedAt:"May 18, 2021",frontMatter:{id:"iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",tags:["csharp","graphs","iterators","iterative"],last_update:{date:"2021-05-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Graphs",permalink:"/ib002/category/graphs"},next:{title:"Distance boundaries from BFS tree on undirected graphs",permalink:"/ib002/graphs/bfs-tree"}},m={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Different implementations",id:"different-implementations",level:2},{value:"Recursive DFS implementation from exercises without colors",id:"recursive-dfs-implementation-from-exercises-without-colors",level:3},{value:"Iterative DFS from the exercises",id:"iterative-dfs-from-the-exercises",level:3},{value:"My iterative with path in stack",id:"my-iterative-with-path-in-stack",level:3},{value:"My iterative solution with iterators",id:"my-iterative-solution-with-iterators",level:3},{value:"Implementation",id:"implementation",level:2}],p={toc:l},c="wrapper";function h(e){let{components:t,...a}=e;return(0,r.kt)(c,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"pathname:///files/ib002/graphs/iterative-and-iterators.tar.gz"},"Source code used later on."))),(0,r.kt)("p",null,"As we have talked on the seminar, iterative approach to implementing DFS is not very intuitive and is a very easy way how to create an incorrect implementation."),(0,r.kt)("p",null,"On the other hand, we have seen iterative implementation in the exercises and I have also prepared two from which one was similar to recursive implementation without colors from exercises and the other one used features of high-level languages."),(0,r.kt)("h2",{id:"different-implementations"},"Different implementations"),(0,r.kt)("h3",{id:"recursive-dfs-implementation-from-exercises-without-colors"},"Recursive DFS implementation from exercises without colors"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"function VisitedDFS(u: Vertex, visited: VertexSet) return VertexSet is\n v: Vertex;\nbegin\n visited.Union(To_Set(u));\n\n for v in u.successors loop\n if not Contains(visited, v) then\n visited := visitedDFS(v, Visited);\n end if;\n end loop;\n\n return visited;\nend VisitedDFS;\n")),(0,r.kt)("p",null,"This implementation is correct, does the DFS traversal as it should, however it has one \u201csmallish\u201d downside and that is the time complexity. The usage of set raises the time complexity, of course it is implementation dependant. However in case of either RB-tree or hash-table implementation, we get look-up in time ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")")))))," for hash-table in worst-case or ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"log"),(0,r.kt)("mo",{parentName:"mrow"},"\u2061"),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\log n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mop"},"lo",(0,r.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")")))))," for the other in the worst-case. Both are not ideal compared to checking color on vertex."),(0,r.kt)("h3",{id:"iterative-dfs-from-the-exercises"},"Iterative DFS from the exercises"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure IterDFS(u: Vertex) is\n stack: StateVector;\n i, time: Integer;\n v: Vertex;\nbegin\n stack.Append(VertexState(u, 0));\n u.color := Gray;\n time := 1;\n u.d := time;\n\n while not stack.Is_Empty loop\n u := stack.Last_Element.Vertex;\n i := stack.Last_Element.NextIndex;\n stack.Delete_Last;\n\n if i < u.successors.Length then\n -- search is not finished, is pushed back to stack\n stack.Append(VertexState(u, k + 1));\n\n v := u.successors.Element(i);\n if v.color = White then\n stack.Append(VertexState(v, 0));\n v.color := Gray;\n time := time + 1;\n v.d := time;\n end if;\n else\n -- u has no other successors, we can finish the search\n time := time + 1;\n u.f := time;\n u.color := Black;\n end if;\n end loop;\n\nend IterDFS;\n")),(0,r.kt)("p",null,"As we can see, there is some ordering in which we search through the successors. Time complexity is OK, stack holds at most all vertices (they must be on the current path)."),(0,r.kt)("h3",{id:"my-iterative-with-path-in-stack"},"My iterative with path in stack"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure DFS(start: Vertex) is\n path: VertexVector;\n time: Integer;\n hasSuccessor: Bool;\n successor: Vertex;\nbegin\n path.Append(start);\n time := 1;\n\n start.d := time;\n start.color := Gray;\n\n while not path.Is_Empty loop\n hasSuccessor := false;\n\n for successor in path.Last_Element.successors loop\n if successor.color = White then\n hasSuccessor := true;\n\n successor.d := time + 1;\n successor.color := Gray;\n time := time + 1;\n\n path.Append(successor);\n\n exit;\n end if;\n end loop;\n\n if not hasSuccessor then\n path.Last_Element.f := time + 1;\n path.Last_Element.color := Black;\n\n time := time + 1;\n path.Delete_Last;\n end if;\n\n end loop;\nend DFS;\n")),(0,r.kt)("p",null,"This approach is similar to the iterative solution from the exercises, but it does not keep the index of the next successor, therefore it always iterates through all of them, which raises the time complexity."),(0,r.kt)("h3",{id:"my-iterative-solution-with-iterators"},"My iterative solution with iterators"),(0,r.kt)("p",null,"On the other hand, we do not actually have to depend on the representation of the graph. In this case, we just ",(0,r.kt)("em",{parentName:"p"},"somehow")," obtain the iterator (which yields all of the succesors) and keep it in the stack."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure DFS(start: Vertex) is\n path: StateVector;\n time: Integer;\n current: State;\n nextVertex: Vertex;\nbegin\n path.Append(State(start));\n time := 1;\n\n start.d := time;\n start.color := Gray;\n\n while not path.Is_Empty loop\n current := path.Last_Element;\n\n if not Move_Next(current.successors) then\n path.Delete_Last;\n\n time := time + 1;\n current.vertex.f := time;\n\n current.vertex.color := Black;\n else if current.successors.Value.color = white then\n nextVertex := current.successors.Value;\n\n time := time + 1;\n nextVertex.d := time;\n\n nextVertex.color := Gray;\n\n path.Append(State(nextVertex));\n end if;\n end loop;\nend DFS;\n")),(0,r.kt)("p",null,"( The way we manipulate with the iterators is closest to the C# implementation. Apart from the ",(0,r.kt)("inlineCode",{parentName:"p"},"Iterator")," thing :) In case you tried to implement it in C++, you would more than likely need to change the check, since you would get first successor right at the beginning )"),(0,r.kt)("p",null,"So here we don't keep indices, but the iterators. We can also check existence of other successors easily: by the iterator moving after the last successor."),(0,r.kt)("p",null,"Closer explanation of the ",(0,r.kt)("em",{parentName:"p"},"iterator shenanigans")," follows. In the beginning, either ",(0,r.kt)("inlineCode",{parentName:"p"},"start")," or when pushing new vertex, we are pushing an iterator that points ",(0,r.kt)("em",{parentName:"p"},"just before")," the first successor. When populating ",(0,r.kt)("inlineCode",{parentName:"p"},"lastVertex")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"successors")," in the ",(0,r.kt)("inlineCode",{parentName:"p"},"while"),"-loop, we take the element from the top of the stack. ",(0,r.kt)("inlineCode",{parentName:"p"},"MoveNext")," returns ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," if there is an element, i.e. successor in this case. If it returns ",(0,r.kt)("inlineCode",{parentName:"p"},"false")," we have nothing to do and we pop the vertex from the stack (also set finishing time and color). If we have successor we check if it has been already visited or not. If has not, we set discovery time and color accordingly, also we add it to stack."),(0,r.kt)("h2",{id:"implementation"},"Implementation"),(0,r.kt)("p",null,"In case you want to play around with the code. At the beginning there is a link to the C# implementation that can be used. It has a basic representation of graph and includes BFS/DFS implementation in classes."),(0,r.kt)("p",null,"In ",(0,r.kt)("inlineCode",{parentName:"p"},"Program.cs")," you can also find a method that returns graph we used on the seminar."))}h.isMDXComponent=!0}}]);