depth first search c program traverse graph
Цей підручник охоплює пошук у глибину (DFS) у C ++, в якому обводиться графік або дерево по глибині. Ви також дізнаєтесь алгоритм та впровадження DFS:
Пошук із глибиною (DFS) - це ще одна техніка, що використовується для обходу дерева або графіка.
DFS починається з кореневого вузла або стартового вузла, а потім досліджує сусідні вузли поточного вузла, заглиблюючись у графік або дерево. Це означає, що в DFS вузли досліджуються поглиблено, поки не зустрінеться вузол без дочірніх елементів.
Після досягнення листового вузла DFS повертається назад і починає досліджувати ще кілька вузлів подібним чином.
=> Зверніть увагу на навчальний посібник для початківців C ++ тут.
Що ви дізнаєтесь:
Глибина першого пошуку (DFS) у C ++
На відміну від BFS, в якому ми досліджуємо вузли вшир, у DFS ми досліджуємо вузли поглиблено. У DFS ми використовуємо структуру даних стеку для зберігання досліджуваних вузлів. Ребра, що ведуть до незвіданих вузлів, називаються 'ребрами відкриття', а ребра, що ведуть до вже відвіданих вузлів, називаються 'ребрами блоків'.
Далі ми побачимо алгоритм і псевдокод для техніки DFS.
Алгоритм DFS
- Крок 1: Вставте кореневий вузол або початковий вузол дерева або графік у стек.
- Крок 2: Витягніть верхній елемент із стеку та додайте його до списку відвідуваних.
- Крок 3: Знайдіть усі сусідні вузли вузла, позначеного відвіданим, і додайте ті, які ще не відвідані, до стеку.
- Крок 4 : Повторюйте кроки 2 і 3, поки стек не порожній.
Псевдокод
Псевдокод для DFS наведено нижче.
З наведеного вище псевдокоду ми помічаємо, що алгоритм DFS викликається рекурсивно на кожній вершині, щоб забезпечити відвідування всіх вершин.
Обхід з ілюстраціями
Проілюструємо тепер обхід DFS графіка. Для наочності ми будемо використовувати той самий графік, що і на ілюстрації BFS.
Нехай 0 - початковий вузол або вузол джерела. Спочатку ми позначаємо його як відвідане та додаємо до списку відвідуваних. Потім ми штовхаємо всі сусідні вузли в стеку.
Далі ми беремо один із сусідніх вузлів для обробки, тобто верх стека, який дорівнює 1. Ми позначаємо його як відвіданий, додаючи до списку відвідуваних. Тепер знайдіть сусідні вузли 1. Оскільки 0 вже є в списку відвідуваних, ми ігноруємо його і відвідуємо 2, який є вершиною стека.
Далі ми позначаємо вузол 2 як відвіданий. Сусідній вузол 4 додається до стека.
Далі ми позначаємо 4, яка є верхньою частиною стека під час відвідування. Вузол 4 має лише вузол 2 як сусідній, який вже відвідано, отже, ми його ігноруємо.
На цьому етапі в стеку присутній лише вузол 3. Сусідній вузол 0 уже відвіданий, тому ми його ігноруємо. Зараз ми відзначаємо 3 як відвідані.
Тепер стек порожній, а в переглянутому списку відображається послідовність обходу першої глибини даного графіка.
Якщо ми спостерігаємо за даним графіком та послідовністю обходу, ми помічаємо, що для алгоритму DFS ми дійсно проходимо графік по глибині, а потім повертаємо його назад, щоб дослідити нові вузли.
Реалізація пошуку по глибині
Давайте реалізуємо техніку обходу DFS за допомогою C ++.
#include #include using namespace std; //graph class for DFS travesal class DFSGraph { int V; // No. of vertices list *adjList; // adjacency list void DFS_util(int v, bool visited()); // A function used by DFS public: // class Constructor DFSGraph(int V) { this->V = V; adjList = new list(V); } // function to add an edge to graph void addEdge(int v, int w){ adjList(v).push_back(w); // Add w to v’s list. } void DFS(); // DFS traversal function }; void DFSGraph::DFS_util(int v, bool visited()) { // current node v is visited visited(v) = true; cout << v << ' '; // recursively process all the adjacent vertices of the node list::iterator i; for(i = adjList(v).begin(); i != adjList(v).end(); ++i) if(!visited(*i)) DFS_util(*i, visited); } // DFS traversal void DFSGraph::DFS() { // initially none of the vertices are visited bool *visited = new bool(V); for (int i = 0; i < V; i++) visited(i) = false; // explore the vertices one by one by recursively calling DFS_util for (int i = 0; i < V; i++) if (visited(i) == false) DFS_util(i, visited); } int main() { // Create a graph DFSGraph gdfs(5); gdfs.addEdge(0, 1); gdfs.addEdge(0, 2); gdfs.addEdge(0, 3); gdfs.addEdge(1, 2); gdfs.addEdge(2, 4); gdfs.addEdge(3, 3); gdfs.addEdge(4, 4); cout << 'Depth-first traversal for the given graph:'< Вихід:
Обхід першої глибини для даного графіка:
0 1 2 4 3
Ми ще раз використали графік у програмі, яку використовували для ілюстративних цілей. Ми бачимо, що алгоритм DFS (розділений на дві функції) викликається рекурсивно на кожній вершині графіка, щоб забезпечити відвідування всіх вершин.
Аналіз виконання
Складність часу DFS така ж, як і BFS, тобто O (| V | + | E |) де V - кількість вершин, а E - кількість ребер у даному графіку.
Подібно до BFS, залежно від того, чи є графік малозаселеним чи густо заселеним, домінуючим фактором будуть вершини або ребра відповідно при розрахунку складності часу.
Ітеративні DFS
Показана вище реалізація для техніки DFS має рекурсивний характер і використовує стек викликів функцій. У нас є інший варіант для реалізації DFS, тобто ' Повторний глибокий пошук '. У цьому ми використовуємо явний стек, щоб утримувати відвідані вершини.
Нижче ми показали реалізацію ітеративного DFS. Зверніть увагу, що реалізація така ж, як BFS, за винятком того фактора, що ми використовуємо структуру даних стеку замість черги.
#include using namespace std; // graph class class Graph { int V; // No. of vertices list *adjList; // adjacency lists public: Graph(int V) //graph Constructor { this->V = V; adjList = new list(V); } void addEdge(int v, int w) // add an edge to graph { adjList(v).push_back(w); // Add w to v’s list. } void DFS(); // DFS traversal // utility function called by DFS void DFSUtil(int s, vector &visited); }; //traverses all not visited vertices reachable from start node s void Graph::DFSUtil(int s, vector &visited) { // stack for DFS stack dfsstack; // current source node inside stack dfsstack.push(s); while (!dfsstack.empty()) { // Pop a vertex s = dfsstack.top(); dfsstack.pop(); // display the item or node only if its not visited if (!visited(s)) { cout << s << ' '; visited(s) = true; } // explore all adjacent vertices of popped vertex. //Push the vertex to the stack if still not visited for (auto i = adjList(s).begin(); i != adjList(s).end(); ++i) if (!visited(*i)) dfsstack.push(*i); } } // DFS void Graph::DFS() { // initially all vertices are not visited vector visited(V, false); for (int i = 0; i < V; i++) if (!visited(i)) DFSUtil(i, visited); } //main program int main() { Graph gidfs(5); //create graph gidfs.addEdge(0, 1); gidfs.addEdge(0, 2); gidfs.addEdge(0, 3); gidfs.addEdge(1, 2); gidfs.addEdge(2, 4); gidfs.addEdge(3, 3); gidfs.addEdge(4, 4); cout << 'Output of Iterative Depth-first traversal:
'; gidfs.DFS(); return 0; }
Вихід:
Вихід ітеративного обходу глибини:
0 3 2 4 1
Ми використовуємо той самий графік, що і в нашій рекурсивній реалізації. Різниця у результатах полягає в тому, що ми використовуємо стек в ітеративній реалізації. Оскільки стеки відповідають порядку LIFO, ми отримуємо іншу послідовність DFS. Щоб отримати ту саму послідовність, ми можемо захотіти вставити вершини в зворотному порядку.
BFS проти DFS
Наразі ми обговорили обидва способи обходу графіків, тобто BFS та DFS.
А тепер давайте розглянемо відмінності між ними.
BFS DFS Стенди для пошуку за шириною Стенд для пошуку глибини спочатку Вузли досліджуються по ширині по рівнях. Вузли досліджуються поглиблено, поки не залишаються лише листові вузли, а потім повертаються назад для дослідження інших невідвіданих вузлів. BFS виконується за допомогою структури даних черги. DFS виконується за допомогою структури даних стеку. Повільніше у виконанні. Швидше, ніж BFS. Корисно знайти найкоротший шлях між двома вузлами. Використовується здебільшого для виявлення циклів на графіках.
Застосування DFS
- Виявлення циклів на графіку: Якщо ми знаходимо задній край при виконанні DFS на графіку, то можна зробити висновок, що графік має цикл. Отже, DFS використовується для виявлення циклів на графіку.
- Пошук шляху: Враховуючи дві вершини x та y, ми можемо знайти шлях між x та y, використовуючи DFS. Ми починаємо з вершини x, а потім штовхаємо всі вершини на шляху до стеку, поки не зустрінемо y. Вміст стеку вказує шлях між x та y.
- Мінімальне обширне дерево та найкоротший шлях: DFS обхід незваженого графіка дає нам мінімальне дерево, що охоплює, і найкоротший шлях між вузлами.
- Топологічне сортування: Ми використовуємо топологічне сортування, коли нам потрібно запланувати завдання із заданих залежностей серед завдань. У галузі інформатики ми використовуємо його здебільшого для вирішення залежностей символів у лінкерах, серіалізації даних, планування інструкцій тощо. DFS широко використовується при топологічному сортуванні.
Висновок
В останніх кількох навчальних посібниках ми детальніше вивчили два прийоми обходу для графіків, тобто BFS та DFS. Ми бачили відмінності, а також застосування обох методів. BFS і DFS в основному досягають однакових результатів відвідування всіх вузлів графіка, але вони відрізняються в порядку виводу та способу, яким це робиться.
Ми також бачили реалізацію обох методик. Поки BFS використовує чергу, DFS використовує стеки для реалізації техніки. На цьому ми закінчуємо навчальний посібник з методів обходу графіків. Ми також можемо використовувати BFS та DFS на деревах.
основні запитання та відповіді на досвідчені інтерв’ю у Java
Ми дізнаємось більше про охоплення дерев та пару алгоритмів, щоб знайти найкоротший шлях між вузлами графіка в нашому майбутньому уроці.
=> Дивіться тут, щоб ознайомитися з повним списком підручників з C ++.
Рекомендована література
- Програма першого пошуку (BFS) C ++ для обходу графіка чи дерева
- Бінарне дерево пошуку C ++: Впровадження BST та операції з прикладами
- Структура даних дерева B та дерева B + у C ++
- Поглиблені підручники Eclipse для початківців
- Структура даних двійкового дерева в C ++
- Впровадження графіків у C ++ із використанням списку суміжності
- Структура даних дерева та купи AVL у C ++
- 12 найкращих інструментів для створення лінійних графіків для створення приголомшливих лінійних графіків (2021 РЕЙТИНГИ)