程序的空间复杂度与存储有关
时间复杂度与算法次数有关, 是最差情况下大致的程序运行次数。程序运行时间 = 时间复杂度 * 一次运算所需要的时间 。
时间复杂度写法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)
图就是能相互链接的数据结构。分为有向图和无向图。个人认为是数据结构中最有趣的部分,能帮助解决很多问题。
该算法,在生活中应用十分常见。比如地图导航。游戏寻路等等
例子:几个节点之间,相连接的线段有固定长度,该长度决就是通过代价。查找到花费最少的路径。该图结构为
可以看到 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米
有权图,理论上来说把权化为等量节点,也可以使用最短节点算法求最短路径。