C# 算法系列一基本数据结构
一、简介
作为一个程序员,算法是一个永远都绕不过去的话题,虽然在大学里参加过ACM的比赛,没记错的话,浙江赛区倒数第二,后来不知怎么的,就不在Care他了,但是现在后悔了,非常的后悔!!!如果当时好好学算法的话,现在去理解一些高深的框架可能会很easy,现在随着C#基础和Web技能的提升,发现哪里都用到算法,但是,很无奈.所以,从今天开始,要重新对自己定位,不能做一个工具的使用者.起码要做到知其所以然.好了,废话不多说,算法之旅,算是正式开始了.希望这个过程能贯穿我的整个职业生涯.甚至整个人生.
二、队列
关于队列,不多说,只要做了一两年程序员,对他肯定不陌生,可以说哪里都有他.关于他的概念也很简单.类似于我们生活中的排队打饭,当然先排队的肯定先打到饭.专业术语叫做先进先出.下面用基于object数组的C#实现,代码如下:
/// <summary>
/// 自定义队列
/// </summary>
public class Queue
{
private object[] _array; /// <summary>
/// 队列头
/// </summary>
private int _head; /// <summary>
/// 队列尾
/// </summary>
private int _tail; /// <summary>
/// 当前数组的长度
/// </summary>
private int _size; /// <summary>
/// 使用默认构造函数时,给定队列默认的长度4
/// </summary>
public Queue() : this()
{ } /// <summary>
/// 初始化指定容量的队列
/// </summary>
/// <param name="capacity"></param>
public Queue(int capacity)
{
if (capacity < )
{
throw new Exception("初始容量不能小于0");
}
_array = new object[capacity];
_head = ;
_tail = ;
_size = ;
} /// <summary>
/// 入队
/// </summary>
public virtual void Enqueue(object obj)
{
_array[_tail] = obj;
_tail = _tail + ;
_size++;
} /// <summary>
/// 出队
/// </summary>
/// <returns></returns>
public virtual object Dequeue()
{
if (Count == )
{
throw new InvalidOperationException("当前队列为空,无法执行Dequeue操作");
} object result = _array[_head];
_array[_head] = null;
_head = _head + ;
_size--;
return result;
} /// <summary>
/// 当前队列的长度
/// </summary>
public int Count { get { return _size; } }
}
控制台调用代码如下:
class Program
{
static void Main(string[] args)
{
var q = new Queue();
q.Enqueue();
q.Enqueue();
q.Enqueue();
q.Enqueue();
Console.WriteLine("出队:{0},{1},{2},{3}", q.Dequeue(), q.Dequeue(), q.Dequeue(), q.Dequeue());
Console.ReadKey();
}
}
先进先出,但是有问题,上面给定初始长度为4,所以全局数组的长度为4,当你调用Equeue方法5次,数组会报溢出错误,所以,如果当前队列的长度等于我们给它的初始值时,必须进行一个数组的Copy操作,将当前数组拷贝到一个容量更大的数组中去,这里MS采用的算法时,每次乘以2的递增.修改代码如下:
/// <summary>
/// 自定义队列
/// </summary>
public class Queue
{
private object[] _array; /// <summary>
/// 队列头
/// </summary>
private int _head; /// <summary>
/// 队列尾
/// </summary>
private int _tail; /// <summary>
/// 当前数组的长度
/// </summary>
private int _size; /// <summary>
/// 使用默认构造函数时,给定队列默认的长度32
/// </summary>
public Queue() : this()
{ } /// <summary>
/// 初始化指定容量的队列
/// </summary>
/// <param name="capacity"></param>
public Queue(int capacity)
{
if (capacity < )
{
throw new Exception("初始容量不能小于0");
}
_array = new object[capacity];
_head = ;
_tail = ;
_size = ;
} /// <summary>
/// 入队
/// </summary>
public virtual void Enqueue(object obj)
{
if (_array.Length == _size)
{
int capacity = _array.Length * ;
SetCapacity(capacity);
}
_array[_tail] = obj;
_tail = _tail + ;
_size++;
} /// <summary>
/// 出队
/// </summary>
/// <returns></returns>
public virtual object Dequeue()
{
if (Count == )
{
throw new InvalidOperationException("当前队列为空,无法执行Dequeue操作");
} object result = _array[_head];
_array[_head] = null;
_head = _head + ;
_size--;
return result;
} /// <summary>
/// 当前队列的长度
/// </summary>
public int Count { get { return _size; } } /// <summary>
/// 重新设定原始数组的容量
/// </summary>
private void SetCapacity(int capacity)
{
var newArray = new object[capacity];
Array.Copy(_array,newArray, _array.Length);
_array = newArray;
_head = ;
_tail = _size;
}
}
ok,现在每次都会以原数组*2的长度扩展原始数组,但是还是有问题,如果这中间存在出队,实际的_size会减一,但是数组实际的长度还是为原来的,区别就是出队的那个元素的位置会被设置为null,会存在以下bug:
var q = new Queue();
q.Enqueue();
q.Dequeue();
q.Enqueue();
q.Enqueue();
q.Enqueue();
q.Enqueue();
Console.WriteLine("出队:{0},{1},{2},{3}", q.Dequeue(), q.Dequeue(), q.Dequeue(), q.Dequeue());
Console.ReadKey();
出队,导致_size-1,但是原始数组的长度还是为4,千万不要说,Dequeue的时候,让第一个元素的内存释放数组长度变为3,这是不可能的,至少我不知道.所以,这里还需要对算法进行改进.好了,到这里我就做不下去了,看了MS的实现,估计是对数组对了特殊的内存处理,没有办法处理出队后第一个元素为null,但是它还是会算到计算长度里面去,如果引入新的变量去计算实际的长度,不用说,m目测会有内存浪费!mmp.如果你们有好的办法,请告知.
通过学习链表发现,队列可以使用环形链表来实现.关于链表请参考随笔.这里因为MS已经提供了API,所以这里不想继续下去了.如果你理解了链表的原理,通过他来实现队列和栈很简单.但是可能无法实现MS原生的队列那样的效果.
C# 算法系列一基本数据结构的更多相关文章
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- 数据结构与算法系列——排序(4)_Shell希尔排序
1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
- 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解
数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...
- Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fix 算法系列补充.docx Atiitt 兼容性提示的艺术 attilax总结.docx Atitit 应用程序容器化总结 v2 s66.docx Atitit file cms api
Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fi ...
- 玩转算法系列--图论精讲 面试升职必备(Java版)
第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...
- 简答一波 HashMap 常见八股面试题 —— 算法系列(2)
请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注 ...
- JAVA算法系列 冒泡排序
java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...
- JAVA算法系列 快速排序
java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...
随机推荐
- java.lang.ClassNotFoundException: org.apache.juli.logging.LogFactory的解决办法
Tomcat7早就出来正式版,但是一直都没有用过,尤其是针对于我还一直在用Myeclipse6.5的人来说,它在配置tomcat的时候没有tomcat7的选项,所以就报了错误信息. java.lang ...
- 以太坊虚拟机(EVM)
转载链接:https://ethfans.org/posts/solidity-chapter1-introduciton-to-smart-contracts 概括总览: 以太坊虚拟机(EVM)是以 ...
- 安卓修改开机logo
这里我们是在ubuntu下进行操作我是用root用户登陆的,首先安装netpbm库 执行:apt-get install netpbm 对于Android系统最开始表现logo是在内核当中,所以首先我 ...
- 重启随机游走算法(RWR:Random Walk with Restart)
1 pagerank算法的基本原理 Pagerank算法是Google的网页排名算法,由拉里佩奇发明.其基本思想是民主表决.在互联网上,如果一个网页被很多其他网页所链接,说明它受到普遍的承认和信赖,那 ...
- (求凹包) Bicycle Race (CF 659D) 简单题
http://codeforces.com/contest/659/problem/D Maria participates in a bicycle race. The speedway t ...
- War Chess (hdu 3345)
http://acm.hdu.edu.cn/showproblem.php?pid=3345 Problem Description War chess is hh's favorite game:I ...
- 【python-ini】python读写ini文件
[python-ini]python读写ini文件 本文实例讲述了Python读写ini文件的方法.分享给大家供大家参考.具体如下: 比如有一个文件update.ini,里面有这些内容: 1 2 ...
- 3、利用GDB进行程序调试
本文将用一个实际例子讲解如何通过GDB进行程序调试. 首先,我们需要理解的是GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,其产生和调试的目的是让调试者知道,程序在执行时内部发生了什么 ...
- 主题模型之潜在语义分析(Latent Semantic Analysis)
主题模型(Topic Models)是一套试图在大量文档中发现潜在主题结构的机器学习模型,主题模型通过分析文本中的词来发现文档中的主题.主题之间的联系方式和主题的发展.通过主题模型可以使我们组织和总结 ...
- AngularJS 单元测试 Karma jasmine
当AngularJS项目越来越大时候,需要进行单元测试,可以先开发功能再进行测试,也可以先进行测试. 一.karma 是一个基于Node.js(先要安装)的JavaScript测试执行过程管理工具( ...