【 基础知识】轻松实现基本数据结构、时间复杂度、加权有向图,加权无向图的最短路径算法、排序算法等

程序的空间复杂度与时间复杂度

程序的空间复杂度与存储有关
时间复杂度与算法次数有关, 是最差情况下大致的程序运行次数。程序运行时间 = 时间复杂度 * 一次运算所需要的时间 。
时间复杂度写法O(n)
n次运算的复杂度是O(n)
二分查找的时间复杂度是 O(log n) 就是求以2为底,n的对数 ,比如log2 8 = 3,因为2的3次幂等于8 (log n = log2 n = (2的x次幂 = n) = x ,)

排序算法

排序算法,存在的意义在于提升搜索效率,或满足某些搜索方式的基础条件。

选择排序法

时间复杂度:O(nn)
不断的对比集合中的元素,依次取出最大/最小的元素,按顺序放入一个新集合中。
例子:有1-100的随机排列的集合,需要按从小到大的顺序排列。第一次对比,取出其中最小的元素1,放入新的集合第一位,然后第二次对比,取出剩余集合中最小的元素2,放入新的结合第二位…

查找算法

数据存在的意义,就是为了被查询。查找算法是重要的基础。

普通查找

时间复杂度 :O(n)
普通查找就是按顺序一个一个的找。也就是傻找。
如果一个集合有n个元素,那么查找到指定元素的最坏次数是n次。 复杂度表示为O(n)
例子:在100个元素中查找指定的元素。如果运气好,第一个就能找到,复杂度为O(1),运气不好第100个才找到,复杂度为O(100)

二分查找

时间复杂度:O(log n)
二分查找是每次都从当前集合的中间取一个元素来比较大小,每次都会淘汰一半的比较集合。
二分查找效率明显,被搜索元素所在的集合越大,查询效率越高。但二分查找只适合有序集合,比如1-100,a-z,乱序无法直接使用,需要先排序。二分查找的
例子:在1,2,3 …100的集合中查找79,先取1-100中间数 =50 与75比较,再取50与100中间数 = 75 与75比较。直到结果相等.

二叉树查找

时间复杂度 :插入、查找、删除O(log n)

数据结构

数据结构,为了满足算法而存在的一种数据关系。

数组

特点:数组可以在内存中存储连续的多个元素的结构,通过数组下标进行访问,下标从0开始。
优点:按索引查询和遍历比较快,
缺点:无法扩容,添加删除比较慢因为要移动其他元素,只能存储一种元素。
时间复杂度:
读取:O(1)
添加:O(n) 因为要移动其他元素
删除:O(n)

链表

特点:链表是非顺序非连续的结构,数据的逻辑顺序是根据指针地址实现的,每个元素包含两个节点,一个是存储数据的内存,另一个是指向下一个节点地址的指针。链表包含单向,双向,循环链表。
优点:链表并不要求内存地址连续排列,因此拥有很好的扩展性,
缺点:当想搜索某个元素时,并不能直接到达该内存位置,而必须从第一个元素依次查找直到指定位置,因为链表的内存地址都记录在上一个元素里面。由于要存储下一个内存地址,所以空间要求大
时间复杂度:
读取:O(n) 查找元素需要遍历所以非常耗时
添加:O(1) 添加删除只是改变指针地址,所以速度很快。
删除:O(1)

特点:先进后出。栈是一种线性表,只能在一端操作,就像一个杯子只能从上进出。加入数据是进栈,取数据是出栈。
优点:符合先进后出的顺序操作需求

队列

特点:先进先出。队列与栈不同,像买票排队一样,一头进,另一头出。
优点:符合先进先出的顺序操作需求

特点:不需要初始化,可以任意加减元素,,但因为包含大量指针所以占用空间较大。。

树是一种有层次关系的集合。就像一树根一样。
树状结构,最大的用途在于方便查找。在数据的增删改时,保持目标树结构的基本规则,即可方便使用诸如2分查找的方法定位数据地址。
树包括二分树,平衡树,红黑树b+ b* avl等
二分树的复杂度最坏情况为O(n)
红黑树的复杂度为O(log n)

散列表(哈希,字典等,arrylist,hashtable等等)

特点:散列表的数据以键值对形式出现,一个键名映射一个内存地址。散列表是十分方便的数据结构,目前高级语言都有它的身影。
优点:速度快,kv形式方便逻辑使用。
缺点:不适合存储过多数据
时间复杂度:
添加删除读取都是 O(1)

图就是能相互链接的数据结构。分为有向图和无向图。个人认为是数据结构中最有趣的部分,能帮助解决很多问题。

无权图的最少节点算法
有权有向图的最短路径查找算法

该算法,在生活中应用十分常见。比如地图导航。游戏寻路等等
例子:几个节点之间,相连接的线段有固定长度,该长度决就是通过代价。查找到花费最少的路径。该图结构为

5米
2米
4米
5米
2米
2米
2米
8米
起点A
B
C
F
终点D

可以看到 A>B>D与A>C>D 的代价都相同,边相加都等于10. 而A>C>B的路线代价扽与9,是最短路径。
思路:

  1. 将每个节点的子节点包括路径都保存成散列表。
  2. 递归检查每个相关节点,看是否能到达终点,并记录下代价、路线、并保存好与上次成功到达终点的路径相比,代价较小的路径。
  3. 不断更新直到循环每个节点。
  4. 最后输出的结果就是想要的最短路径

复杂度:最坏情况应该就是O((n-1)2) 了吧
此段代码,用于求出任意两点间的所有路径

//csharp版代码,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace ConsoleApp1test
{
    class Program
    {   //创建图数据
        static Hashtable myGraph = new Hashtable();
        static void Main(string[] args) 
        {
            //A节点及其信息与关系
            myGraph["A"] = new Hashtable();
            (myGraph["A"] as Hashtable)["B"] = 5;
            (myGraph["A"] as Hashtable)["C"] = 2;
            (myGraph["A"] as Hashtable)["F"] = 2;
            //B节点
            myGraph["B"] = new Hashtable();
            (myGraph["B"] as Hashtable)["D"] = 5;
            (myGraph["B"] as Hashtable)["F"] = 5;
            //C
            myGraph["C"] = new Hashtable();
            (myGraph["C"] as Hashtable)["B"] = 2;
            (myGraph["C"] as Hashtable)["D"] = 8;
            //D
            myGraph["D"] = new Hashtable();
            //f
            myGraph["F"] = new Hashtable();
            //递归监测
            GetPath(myGraph["A"] as Hashtable, "A", "D");
           
            Console.ReadKey();
        }

        //创建用于存储代价的变量
        static int cost = 0;
        //创建用于记录路径的数据表
        static Hashtable rote = new Hashtable();
        static List<string> rotearray = new List<string>();
        public static void GetPath(Hashtable targetNode, string startPoint, string endPoint)
        {
            //记录当前节点
            rotearray.Add(startPoint);
            Console.WriteLine("当前节点:"+ startPoint);
            string st = "";
            foreach (string name in rotearray)
            {
                st += name + ">";
            }
            Console.WriteLine("当前结构:"+st);
            //当前节点是否是根节点
            if (startPoint == endPoint)
            {
                //已经到达终点  //输出当前分支的每个节点
                string s = "";
                foreach (string name in rotearray)
                {
                    s += name + ">";
                }
                Console.WriteLine("到达终点,路径:"+s);
                Console.WriteLine("=================");
            } else {
                //未到达指定节点 遍历每个节点下相关联的子节点
                foreach (string connected_node_name in targetNode.Keys)//在第一次输入时,不应该遍历所有的值
                {
                    GetPath(myGraph[connected_node_name] as Hashtable, connected_node_name, endPoint);
                }
            }

            //删除当前节点回 到上层
            if (rotearray.Count > 0)
                rotearray.RemoveAt(rotearray.Count - 1);
        }
    }
}

结果:

当前节点:A
当前结构:A>
当前节点:C
当前结构:A>C>
当前节点:D
当前结构:A>C>D>
到达终点,路径:A>C>D>
=================
当前节点:B
当前结构:A>C>B>
当前节点:F
当前结构:A>C>B>F>
当前节点:D
当前结构:A>C>B>D>
到达终点,路径:A>C>B>D>
=================
当前节点:F
当前结构:A>F>
当前节点:B
当前结构:A>B>
当前节点:F
当前结构:A>B>F>
当前节点:D
当前结构:A>B>D>
到达终点,路径:A>B>D>
=================

更新指定两点 最短路径啦

此段代码,用于求出加权图最短路径,加入了防循环,可以在有向图、无向图中使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace ConsoleApp1test
{
    class Program
    {   
    	//创建图数据
        static Hashtable myGraph = new Hashtable();
        static void Main(string[] args) 
        {
            //A节点及其信息与关系
            myGraph["A"] = new Hashtable();
            (myGraph["A"] as Hashtable)["B"] = 5;
            (myGraph["A"] as Hashtable)["C"] = 2;
            (myGraph["A"] as Hashtable)["F"] = 2;
            //B节点
            myGraph["B"] = new Hashtable();
            (myGraph["B"] as Hashtable)["D"] = 5;
            (myGraph["B"] as Hashtable)["F"] = 5;
            //C
            myGraph["C"] = new Hashtable();
            (myGraph["C"] as Hashtable)["B"] = 2;
            (myGraph["C"] as Hashtable)["D"] = 8;
            //D
            myGraph["D"] = new Hashtable();
            //f
            myGraph["F"] = new Hashtable();
            (myGraph["F"] as Hashtable)["B"] = 2;
            //递归监测
            GetPath(myGraph["A"] as Hashtable, "A", "D");
            Console.WriteLine("最短路径:" + shortestPath + " 代价:" + shortestCost + "米");
            Console.ReadKey();
        }

        //创建用于存储代价\记录路径的数据表
        static List<string> pathList = new List<string>();
        static List<int> pathCostList = new List<int>();
        static int shortestCost = 100000;
        static string shortestPath = "";

        public static void GetPath(Hashtable targetNode, string startPoint, string endPoint)
        {
            //记录当前节点
            pathList.Add(startPoint);
            Console.WriteLine("当前节点:"+ startPoint);
            string allPath = "";
            for(int i=0; i < pathList.Count; i++)
            {
                allPath += pathList[i];
                allPath += (i == (pathList.Count - 1)) ? "" : ">";
            }
            Console.WriteLine("当前结构:" + allPath);

            //当前节点是否是根节点
            if (startPoint == endPoint)
            {
                //已经到达终点  //输出当前分支的每个节点
                Console.WriteLine("到达终点,路径:"+ allPath);

                //计算所有的权值
                int pathCost_total = 0;
                foreach (int pathCost in pathCostList)
                {
                    pathCost_total += pathCost;
                }
                Console.WriteLine("代价:" + pathCost_total.ToString() + "米");

                //更新最短路径信息
                if (pathCost_total < shortestCost) {
                    shortestCost = pathCost_total;
                    shortestPath = allPath;
                }
                Console.WriteLine("==========害羞而淫荡的分割线==========");
            } else {
                //未到达指定节点 遍历每个节点下相关联的子节点
                foreach (string connected_node_name in targetNode.Keys)
                {
                    //如果,路径中已存在节点,就不走了。 避免循环。
                    if (!pathList.Contains(connected_node_name)) {
                    //记录路径权值
                    pathCostList.Add((int)targetNode[connected_node_name]);
                    GetPath(myGraph[connected_node_name] as Hashtable, connected_node_name, endPoint);
                    //记录路径权值
                    if (pathCostList.Count > 0)
                        pathCostList.RemoveAt(pathCostList.Count - 1);
                    }
                }
            }

            //删除当前节点回 到上层
            if (pathList.Count > 0)
                pathList.RemoveAt(pathList.Count - 1);
        }
    }
}


结果;

当前节点:A
当前结构:A
当前节点:C
当前结构:A>C
当前节点:D
当前结构:A>C>D
到达终点,路径:A>C>D
代价:10==========害羞而淫荡的分割线==========
当前节点:B
当前结构:A>C>B
当前节点:F
当前结构:A>C>B>F
当前节点:D
当前结构:A>C>B>D
到达终点,路径:A>C>B>D
代价:9==========害羞而淫荡的分割线==========
当前节点:F
当前结构:A>F
当前节点:B
当前结构:A>F>B
当前节点:D
当前结构:A>F>B>D
到达终点,路径:A>F>B>D
代价:9==========害羞而淫荡的分割线==========
当前节点:B
当前结构:A>B
当前节点:F
当前结构:A>B>F
当前节点:D
当前结构:A>B>D
到达终点,路径:A>B>D
代价:10==========害羞而淫荡的分割线==========
最短路径:A>C>B>D 代价:9

有权图,理论上来说把权化为等量节点,也可以使用最短节点算法求最短路径。

你可能感兴趣的:(#,计算机视觉算法相关)