算法入门:搜索算法

文章目录

1.二分查找

2.深度优先搜索(DFS)

3.广度优先搜索(BFS)

4.DFS与BFS区别

 

1.二分查找

思想:二分查找是一种高效的查找算法,它基于分治思想,适用于已排序的数组。

  1. 确定搜索范围: 首先确定整个数组的搜索范围,通常是从数组的起始位置到结束位置。

  2. 计算中间位置: 计算搜索范围的中间位置。

  3. 比较中间元素: 将目标元素与中间位置的元素进行比较。

    • 如果目标元素等于中间位置的元素,查找成功,返回中间位置的索引。
    • 如果目标元素小于中间位置的元素,说明目标元素在左半部分,缩小搜索范围为左半部分。
    • 如果目标元素大于中间位置的元素,说明目标元素在右半部分,缩小搜索范围为右半部分。
  4. 重复搜索: 重复步骤2和步骤3,直到找到目标元素或搜索范围缩小为空。

using System;

class Program
{
    static void Main()
    {
        // 创建一个有序整数数组
        int[] sortedArray = { 11, 22, 34, 45, 55, 67, 78, 89, 99 };

        // 要查找的目标元素
        int target = 55;

        // 调用二分查找算法
        int result = BinarySearch(sortedArray, target);

        // 输出查找结果
        if (result != -1)
        {
            Console.WriteLine($"目标元素 {target} 找到,索引位置为 {result}。");
        }
        else
        {
            Console.WriteLine($"目标元素 {target} 未找到。");
        }
    }

    // 二分查找算法
    static int BinarySearch(int[] arr, int target)
    {
        int low = 0;
        int high = arr.Length - 1;

        // 在搜索范围内进行二分查找
        while (low <= high)
        {
            int mid = (low + high) / 2;

            // 目标元素等于中间位置的元素
            if (arr[mid] == target)
            {
                return mid;
            }

            // 目标元素小于中间位置的元素,缩小搜索范围为左半部分
            else if (target < arr[mid])
            {
                high = mid - 1;
            }

            // 目标元素大于中间位置的元素,缩小搜索范围为右半部分
            else
            {
                low = mid + 1;
            }
        }

        // 没有找到目标元素
        return -1;
    }
}
  • BinarySearch方法: 二分查找的实现。在每一步中,计算中间位置,将目标元素与中间位置的元素进行比较,然后根据比较结果缩小搜索范围。重复这个过程直到找到目标元素或搜索范围为空。

  • 在示例中,我们创建了一个有序整数数组 sortedArray,然后使用二分查找算法查找目标元素 target 的索引位置。如果找到目标元素,输出目标元素的索引位置;如果未找到目标元素,输出未找到的消息。

二分查找是一种高效的查找算法,适用于有序数组。其时间复杂度为O(log n),其中 n 是数组的长度。

 

2.深度优先搜索(DFS)

思想:深度优先搜索(Depth-First Search,DFS)是一种图遍历算法,其基本思想是从图的某个起始节点开始,沿着一条路径尽可能深地访问,直到到达最深处,然后回溯到上一个节点,选择另一条路径继续深度优先遍历,直到遍历完整个图。

深度优先搜索的主要思想包括以下几点:

1. 选择起始节点:选择图中的一个起始节点作为深度优先搜索的起点。

2. 访问节点:访问当前节点,并将其标记为已访问。

3. 探索邻居节点:递归或使用栈来探索当前节点的邻居节点,选择一个未被访问的邻居节点,重复步骤2。

4. 回溯:当当前节点的所有邻居节点都被访问过或没有未被访问的邻居节点时,回溯到上一个节点,继续探索未被访问的路径。

5. 重复步骤3和步骤4:重复进行步骤3和步骤4,直到所有节点都被访问过。

深度优先搜索可以使用递归或栈来实现。在递归实现中,通过递归函数来实现对邻居节点的探索;在栈实现中,使用栈来保存需要访问的节点,通过循环不断出栈和入栈来进行深度优先搜索。

深度优先搜索在解决图相关问题时非常有用,例如找图中的路径、判断图的连通性、生成图的拓扑排序等。

using System;
using System.Collections.Generic;

class Graph
{
    private int V; // 图的顶点数
    private List<int>[] adjList; // 邻接表表示图

    public Graph(int vertices)
    {
        V = vertices;
        adjList = new List<int>[V];

        for (int i = 0; i < V; i++)
        {
            adjList[i] = new List<int>();
        }
    }

    // 添加边
    public void AddEdge(int v, int w)
    {
        adjList[v].Add(w);
        adjList[w].Add(v);
    }

    // 深度优先搜索
    public void DFS(int start)
    {
        bool[] visited = new bool[V];
        DFSUtil(start, visited);
    }

    // 深度优先搜索的辅助函数
    private void DFSUtil(int v, bool[] visited)
    {
        // 访问当前节点
        Console.Write(v + " ");
        visited[v] = true;

        // 递归遍历邻居节点
        foreach (int neighbor in adjList[v])
        {
            if (!visited[neighbor])
            {
                DFSUtil(neighbor, visited);
            }
        }
    }
}

class Program
{
    static void Main()
    {
        // 创建一个图并添加边
        Graph graph = new Graph(6);
        graph.AddEdge(0, 1);
        graph.AddEdge(0, 2);
        graph.AddEdge(1, 3);
        graph.AddEdge(2, 4);
        graph.AddEdge(2, 5);

        // 从节点0开始进行深度优先搜索
        Console.WriteLine("深度优先搜索结果:");
        graph.DFS(0);
    }
}
  • Graph类: 表示一个无向图,使用邻接表来存储图的结构。构造函数初始化邻接表,AddEdge方法用于添加边。

  • DFS方法: 深度优先搜索的入口方法,接受起始节点作为参数,初始化访问数组并调用DFSUtil进行深度优先搜索。

  • DFSUtil方法: 深度优先搜索的辅助函数,递归地访问当前节点及其未被访问的邻居节点。

  • Main方法: 在主函数中创建图并添加边,然后从节点0开始进行深度优先搜索,输出搜索结果。

示例中,图的结构使用邻接表表示,通过DFS方法从节点0开始进行深度优先搜索。深度优先搜索的结果是按照访问的顺序输出节点的值。在实际应用中,深度优先搜索可用于解决一些图相关的问题,例如路径查找、连通性检测等。

 

3.广度优先搜索(BFS)

 思想:广度优先搜索(Breadth-First Search,BFS)是一种图遍历算法,其基本思想是从图的某个起始节点开始,首先访问起始节点,然后依次访问与起始节点直接相邻的所有节点,接着访问与这些相邻节点直接相邻的所有未被访问的节点,以此类推,直到遍历完整个图。

BFS通常使用队列来实现,保证先访问的节点先出队列,后访问的节点后出队列。具体思路如下:

1. 选择起始节点:选择图中的一个起始节点作为BFS的起点。

2. 将起始节点入队:将起始节点入队列。

3. 循环遍历队列:循环执行以下步骤,直到队列为空。

  • 出队列:从队列中取出一个节点。
  • 访问节点:访问当前节点。
  • 将未被访问的邻居节点入队:将当前节点的所有未被访问的邻居节点入队列。

4. 重复步骤3:重复执行步骤3,直到队列为空,表示图的所有节点都已被访问。

BFS的关键是使用队列来维护待访问的节点顺序,以确保按层次遍历图。这样可以方便地找到起始节点到其他节点的最短路径,因为在BFS中先访问的节点离起始节点的距离更近。

BFS在解决图的路径问题、连通性检测等方面具有广泛的应用。

using System;
using System.Collections.Generic;

class Graph
{
    private int V; // 图的顶点数
    private List<int>[] adjList; // 邻接表表示图

    public Graph(int vertices)
    {
        V = vertices;
        adjList = new List<int>[V];

        for (int i = 0; i < V; i++)
        {
            adjList[i] = new List<int>();
        }
    }

    // 添加边
    public void AddEdge(int v, int w)
    {
        adjList[v].Add(w);
        adjList[w].Add(v);
    }

    // 广度优先搜索
    public void BFS(int start)
    {
        bool[] visited = new bool[V];
        Queue<int> queue = new Queue<int>();

        // 将起始节点入队
        queue.Enqueue(start);
        visited[start] = true;

        while (queue.Count != 0)
        {
            // 出队列
            int current = queue.Dequeue();
            Console.Write(current + " ");

            // 遍历当前节点的未被访问的邻居节点
            foreach (int neighbor in adjList[current])
            {
                if (!visited[neighbor])
                {
                    // 将未被访问的邻居节点入队
                    queue.Enqueue(neighbor);
                    visited[neighbor] = true;
                }
            }
        }
    }
}

class Program
{
    static void Main()
    {
        // 创建一个图并添加边
        Graph graph = new Graph(6);
        graph.AddEdge(0, 1);
        graph.AddEdge(0, 2);
        graph.AddEdge(1, 3);
        graph.AddEdge(2, 4);
        graph.AddEdge(2, 5);

        // 从节点0开始进行广度优先搜索
        Console.WriteLine("广度优先搜索结果:");
        graph.BFS(0);
    }
}
  • Graph类: 表示一个无向图,使用邻接表来存储图的结构。构造函数初始化邻接表,AddEdge方法用于添加边。

  • BFS方法: 广度优先搜索的实现。使用队列来保存待访问的节点,起始节点入队列后,循环出队列并访问节点,将未被访问的邻居节点入队列。重复这个过程直到队列为空。

  • Main方法: 在主函数中创建图并添加边,然后从节点0开始进行广度优先搜索,输出搜索结果。

示例中,图的结构使用邻接表表示,通过BFS方法从节点0开始进行广度优先搜索。广度优先搜索的结果是按照层次遍历图的节点。在实际应用中,广度优先搜索可用于解决一些图相关的问题,例如路径查找、连通性检测等。

 

4.DFS与BFS区别

深度优先搜索(Depth-First Search,DFS)和广度优先搜索(Breadth-First Search,BFS)是两种常用的图遍历算法,它们在搜索过程中的策略和结果输出上有一些区别。

1. 搜索策略

  • 深度优先搜索(DFS):从起始节点开始,沿着一条路径尽可能深地访问,直到无法继续为止,然后回溯到上一个节点,选择另一条路径继续深度优先遍历。DFS通常使用递归或栈实现。
  • 广度优先搜索(BFS):从起始节点开始,首先访问起始节点,然后依次访问与起始节点直接相邻的所有节点,接着访问与这些相邻节点直接相邻的所有未被访问的节点,以此类推,直到遍历完整个图。BFS通常使用队列实现。

2. 搜索顺序

  • 深度优先搜索(DFS):DFS在遍历图时可能深入到图的很深层次,因此先访问的节点可能离起始节点很远。
  • 广度优先搜索(BFS):BFS按照层次逐层遍历图,先访问的节点离起始节点的距离更近。

3. 数据结构

  • 深度优先搜索(DFS):可以使用递归或栈实现,递归调用或栈操作维护搜索顺序。
  • 广度优先搜索(BFS):** 使用队列来保存待访问的节点,保证按照层次逐层遍历。

4. 应用场景

  • 深度优先搜索(DFS):适用于解决一些路径问题,如找图中的路径,以及对图的连通性进行检测等。
  • 广度优先搜索(BFS):适用于解决一些最短路径问题,如找图中节点到达目标节点的最短路径,以及对图的连通性进行检测等。

总体而言,深度优先搜索和广度优先搜索各有适用的场景,选择哪种算法取决于具体的问题需求。在实际应用中,有些问题可能更适合深度优先搜索,而另一些问题可能更适合广度优先搜索。

 

posted @ 2024-02-18 09:42  程序员胡大圣  阅读(23)  评论(0编辑  收藏  举报