程序的空间复杂度与存储有关 时间复杂度与算法次数有关, 是最差情况下大致的程序运行次数。程序运行时间 = 时间复杂度 * 一次运算所需要的时间 。 时间复杂度写法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)
特点:散列表的数据以键值对形式出现,一个键名映射一个内存地址。散列表是十分方便的数据结构,目前高级语言都有它的身影。 优点:速度快,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,是最短路径。 思路:
将每个节点的子节点包括路径都保存成散列表。递归检查每个相关节点,看是否能到达终点,并记录下代价、路线、并保存好与上次成功到达终点的路径相比,代价较小的路径。不断更新直到循环每个节点。最后输出的结果就是想要的最短路径复杂度:最坏情况应该就是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米有权图,理论上来说把权化为等量节点,也可以使用最短节点算法求最短路径。