一、编写性能测试类(Timing)
- 什么是数据结构
- 数据结构,可以理解为数据的结构,书面意思为群集。群集是一种结构化的数据类型,它存储数据并提供了添加、删除、更新操作。群集可分为线性群集和非线性群集
- 线性群集:是一张元素列表,表中的元素顺次相连。(如第一个元素、第二个元素)计算机中最常见的线性群集是数组链表
- 直接存储群集:也就是说对于群集中的每一个数据元素我们都可以直接存取,通常表现为数组,我们可以直接根据数组下标定位到具体的数据。
我们可以用数组来存储一个线性群集,向数组添加一个新元素或者移除末尾元素是很简单的,只需要把新元素放到数组末尾或者直接从末尾移除既可。
但是,往数组中插入一个元素或者删除除末尾元素意外其他位置的元素就不那么高效了,因为要给插入的元素空出位置,所以其他元素需要按顺序都向后退一位。删除元素也一样,删除的元素后面的元素都需要向前移动一位。
string,就是一种直接存储群集,它是不可变的,比如需要修改字符串,并不是直接修改,而是创建一个副本,在某些情况下这种行为可能会导致性能下降,所以.NET框架提供了StringBuilder类来让用户能处理可变的字符串 - 顺序存储群集:把群集按顺序存储的表,线性表在创建是没有大小限制,这意味着我们可以动态的扩展和收缩。每个元素都是与之关联的,因此我们需要一个个遍历才能访问我们要的某个具体元素不能直接进行存储访问。通常变现为链表。
链表:前一个元素将保存一个元素的指针指向它后面的那个元素,因此,对于插入和删除操作比数组要高效。由于不能直接存取线性表的元素,所以在查找方面比数组效率要低。
线性表的某些类型限制了访问数据的元素,这类线性表为栈和队列。
栈:栈限定只能在表头存储和移除数据,为此栈也被称之为 先进后出 的数据结构。
队列:队列和栈有所不同它限定只能从表头存储,末尾移除,所以为 先进先出 的数据结构。优先队列是队列的一种特殊类型,假设医院门诊,快死的人先诊,然后才是残疾的诊。 - 散列群集:它存储了一组与关键字相关的数据值,在散列表中有一个散列函数,将会取走一个关键字,并把这个关键字转换成用了取回数据的散列索引.HashTable、Dictionary
索引群集对于元素的存取使用关键字定位的方式,索引它在元素的访问效率上接近直接存取集,而添加和删除元素不需要移动原有元素,所以在插入和删除的操作上效率也很高,是一种兼具直接存取集合顺序存取集优点的线性群集。
- 非线性群集:非线性群集没有顺序之分,好比一桌台球,用3角框把球框进来形成一组。计算机中如树、堆、图和集都被设计为非线性群集
- 层次群集:位于某一层的数据项可能会有位于下一较低层上的后继数据项,树、堆被设计为层次群集
- 树:树群集看上去像是一棵倒立的树,其中一个数据项作为根,而其他数据值则作为叶子挂在根的下面。树的元素被称为节点,而且在特定节点下面的元素被称为是此节点的孩子。
- 二叉树:二叉树是一种特殊的树群集,它规定没个根节点下最多只有二个子节点。二叉树可以变为二叉查找树,这样做可以极大的提高大量数据的查找效率,实现方法是依据从根到需要存储数据
的最短路径来放置节点。 - 堆:堆就是为了便于把最小值放置在根节点上,在删除和插入时都会导致堆重组。这样才能保证最小值在根节点,我们经常会用到堆来进行排序,称之为堆排序
- 组群集:数据项为无序的非线性群集被称为组。集合、图和网络是组群集的三种主要类型
- 层次群集:位于某一层的数据项可能会有位于下一较低层上的后继数据项,树、堆被设计为层次群集
- 什么是算法
- 算法是一系列解决问题的治疗,后续将会介绍程序中的各种算法,以及针对不同的问题应当采取哪种算法才是最高效的。那么如何测试算法的性能呢,下一节我们通过编写Timing类来进行性能的监视
- 算法是一系列解决问题的治疗,后续将会介绍程序中的各种算法,以及针对不同的问题应当采取哪种算法才是最高效的。那么如何测试算法的性能呢,下一节我们通过编写Timing类来进行性能的监视
- Timing时间测试类
-
View Codeusing System; using System.Linq; using System.Text; namespace ConsoleApplication7 { class Program { static void Main(string[] args) { int[,] nums = new int[1000, 100]; BuildArray(nums); DateTime startTime = DateTime.Now; TimeSpan endTime; DisplayNums(nums); endTime = DateTime.Now.Subtract(startTime); Console.WriteLine("Time:"+endTime.TotalSeconds); } static void BuildArray(int[,] nums) { for (int i = nums.GetLowerBound(0); i <= nums.GetUpperBound(0); i++) { for (int j = nums.GetLowerBound(1); j <= nums.GetUpperBound(1); j++) { //外层循环i*第二维的元素数 + j nums[i, j] = i*nums.GetLength(1)+ (j + 1); } } } static void DisplayNums(int[,] nums) { for (int i = nums.GetLowerBound(0); i <= nums.GetUpperBound(0); i++) { for (int j = nums.GetLowerBound(1); j <=nums.GetUpperBound(1); j++) { Console.WriteLine(nums[i,j]+""); } } } } }
上述代码在我本机跑 3s 左右,虽然这段代码对执行时间测试好像有道理,但在.NET FRAMWORK中这是不合理的,为什么呢?
首先,时间测量是从子程序调用开始到返回主程序之间流失的时间。但是上述代码也包含了
1:同C#程序同时执行的其他进程所用的时间
2:程序执行无用单元收集的时间
3:GC收集的时间 (每个存在堆上的对象都有一个finalizer的函数,它在执行这个对象收集的前做最后一步,C#编译器不能直接实现该方法)
那么根据上面3个问题给出解决方案:
1:为了避免包含其他进程所用的时间,我们需要获取当前进程执行所需的时间,Process类可以做到这一点System.Diagnostics.Process.GetCurrentProcess().Threads[0].UserProcessorTime2:程序执行无用单元收集一般都是GC在最合适的时间执行的,因此我们不确定啥时候执行单元收集,但是我们可以使用如下代码来强制进行垃圾回收
3:虽然我们强制执行垃圾回收,但是我们并不应该把垃圾回收的时间也算到里边,如下代码可以挂起线程,等GC执行完所有finalizer收集后再继续GC.Collect()
GC.WaitForPendingFinalizers()
这三个问题解决了那么我们就可以着手编写Timing类了。
View Codeusing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication7 { public class Timing { private TimeSpan startTime,duration; public Timing() { startTime = new TimeSpan(0); duration = new TimeSpan(0); } public void Start() { GC.Collect();//force garbage Collection GC.WaitForPendingFinalizers(); startTime = Process.GetCurrentProcess().Threads[0].UserProcessorTime; } public void End() { duration = Process.GetCurrentProcess().Threads[0].UserProcessorTime.Subtract(startTime); } public TimeSpan Result { get { return duration; } } } }
OK,看下如何使用
View Codeusing System; using System.Collections; using System.Linq; using System.Text; namespace ConsoleApplication7 { class Program { static void Main(string[] args) { Collection cb = new Collection(); ArrayList array = new ArrayList(); Timing t = new Timing(); t.Start(); Collection(cb); t.End(); Console.WriteLine(t.Result.TotalSeconds); t = new Timing(); t.Start(); ArrayList(array); t.End(); Console.WriteLine(t.Result.TotalSeconds); } static void Collection(Collection cb) { for (int i = 1; i <= 100000; i++) { cb.Add(i); } } static void ArrayList(ArrayList array) { for (int i = 1; i <= 100000; i++) { array.Add(i); } } } }
-


浙公网安备 33010602011771号