一、简介

作为一个程序员,算法是一个永远都绕不过去的话题,虽然在大学里参加过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# 算法系列一基本数据结构的更多相关文章

  1. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  2. 数据结构与算法系列——排序(4)_Shell希尔排序

    1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...

  3. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  4. 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解

    数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...

  5. 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 ...

  6. 玩转算法系列--图论精讲 面试升职必备(Java版)

    第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...

  7. 简答一波 HashMap 常见八股面试题 —— 算法系列(2)

    请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注 ...

  8. JAVA算法系列 冒泡排序

    java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...

  9. JAVA算法系列 快速排序

    java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...

随机推荐

  1. vs2013查看代码性能后删除保存的性能查看文件导致再打开提示未找到与约束匹配的导出

    1.关闭VS: 2.删除C:/Users//AppData/Local/Microsoft/VisualStudio/12.0/ComponentModelCache文件夹下所有文件及文件夹: 3.重 ...

  2. java web 实现文件夹上传(保留目录结构)

    今天我弄了一下文件夹上传(很简单的 首先,我们的html需要这样写 <form action="/file/upload" enctype="multipart/f ...

  3. xslt 和一个demo

    https://www.w3.org/1999/XSL/Transform Specifications The XSLT language has three versions which are ...

  4. 20170905工作日记--listview优化大全

    1. 适配器设计模式 实例描述:我们国家的电器使用普通的扁平两项或三项插头,而去外国的话,使用的标准就不一样了,比如德国,使用的是两项圆头的插头,那么我们使用的手机充电器插头无法插到德国的插排中去,那 ...

  5. 改Android手机定位位置

    手机定位方法 1,gps等卫星定位,如美国的gps,欧洲的伽利略,中国的北斗等,通过至少三颗卫星,用三角定位和时间等算法,计算出设备的经纬度,到地图上找到这个经纬度的地名 2,移动运营商基站定位,通过 ...

  6. _技巧_SublimeText_打开文件乱码解决

    macOS属于Unix分支,默认使用UTF-8编码,当从Window 或者其他Linux 或 Unix系统 拷贝文件过来,由于Window系统使用GBK或者GB2312中文编码,所以会出现乱码现象. ...

  7. 20169207《Linux内核原理及分析》第十二周作业

    本周选做的信息安全实验为Python实现Zip文件的暴力破解 实验预备: 这次实验我们需要用到的库为zipfile.下来我们先来了解一下这个模块. 首先我们的重点是对zip文件的操作,而zipfile ...

  8. (01背包 第k优解) Bone Collector II(hdu 2639)

    http://acm.hdu.edu.cn/showproblem.php?pid=2639       Problem Description The title of this problem i ...

  9. (动规 或 最短路)Help Jimmy(poj 1661)

    http://poj.org/problem?id=1661 Description "Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的 ...

  10. eclipse中html编辑环境的搭建

    转自http://blog.csdn.net/xuanyuansen/article/details/9318661 最近开始对JAVA网络编程感兴趣,所以索性用起了鼎鼎有名的eclipse,正如广大 ...