二叉树的非递归遍历

Post on by michaelyin

二叉树的遍历如果使用递归调用基本没什么问题,这里主要是讲如何使用非递归方法实现二叉树的遍历。

由于递归调用程序实际上使用了栈来保存方法中的变量值,在非递归遍历的方法中我们需要基于栈的方法。先来看看这个方法

/// <summary>
/// 非递归中序遍历二叉树
/// </summary>
/// <param name="root"></param>
static void InOrderTraverse(BinaryTreeNode root)
{
    BinaryTreeNode temp = root;
    Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
    stack.Push(root);
    while (stack.Count > 0)
    {
        while (temp != null)
        {
            temp = temp.left;
            stack.Push(temp);
        }
        stack.Pop();
        //如果为0证明这时右边节点为null
        if (stack.Count > 0)
        {
            temp = stack.Pop();
            Console.WriteLine(temp.data);
            temp = temp.right;
            stack.Push(temp);
        }
    }
}

节点temp在这里是起一个标识的作用 ...


闲话动态KML

Post on by michaelyin

最近在Google Map开发中开发中用到了动态生成KML在地图中动态显示数据,下面来简单的把其中的知识点讲一下。

KML是一种采用XML 语法与格式的语言,它被用来描述地理信息,如点,线,多边形等等,可以被Google map和Google Earth等软件识别并显示。我们可以在Google Earth把我们感兴趣的一些地点标识出来,然后生成KML文件,通过分享这个文件来让别人在Google map或者google earth中看到我们标注的信息。下面是一个简单的KML文件。

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <Placemark>
    <name>Simple placemark</name>
    <description>Attached to the ground. Intelligently places itself 
       at the height of the underlying terrain.</description>
    <Point>
      <coordinates>-122.0822035425683,37.42228990140251,0</coordinates>
    < ...

算法学习之快速排序

Post on by michaelyin

快速排序通常是用于排序的最佳实用选择,因为它的平均性能相当好。

快速排序和先前讲到的合并排序一样,体现了算法设计中的分治的思想。我们首先将问题进行分解,将数组划分成两个部分A[p…q-1]和A[q+1…r],使得A[p…q-1]中的元素小于等于A[q],然后分别解决前面一个数组和后面一个数组的排序,最后进行合并,由于这两个数组是就地排序(in place)的,所以不用像合并排序中一样进行过多的合并的操作。

由于中间的分别排序的部分可以使用递归实现,所以快速排序中关键的地方就是如何将数组进行分解了。

/// <summary>
/// 对数组进行分组,返回分界处的index
/// </summary>
public static int Partition(int[] array, int firstIndex, int secIndex)
{
    int key = array[secIndex];
    int k = firstIndex;
    for (int j = firstIndex; j < secIndex; j++)
    {
        if (array[j] < key)
        {
            Utils.Swap(ref array[k], ref array[j]);
            k ...

由类能否包含自己说开去

Post on by michaelyin

下午在Coding的时候突然想到了一个问题,类到底能不能包含自己?在什么情况下能包自己?

当时正在实现一个类似链表的功能,在一个节点中需要有下个节点的引用的数据,比如像这样子的代码。

public class Node
{
    public int data;
    public Node Next;
}

在Node中有一个Node类型的引用地址,用来找到这个节点的下一个节点。默认构造函数调用后会将data置0,Next置null,当时我写到这里突然想起来好像在哪里看到过类中包含类自己是不行的。于是在Console中跑了一遍,运行结果是对的。断点显示初始化的值是我预计的结果。那到底在什么情况下类不能包含自己呢?要知道答案,我们还是先要说说初始化背后的故事。

在我初始化节点的时候我调用的是new Node()这个方法,这个时候.Net会首先计算类中成员需要的内存空间,这里就是int类型和Node引用类型的地址的空间(实际还有别的,不过和我们讨论的问题无关,故在这里省略),然后在内存中分配内存空间,分配了内存空间后就会对类中的变量进行初始化,比如我的代码中写的是public int data = 3;那么data这个变量就会在这时被赋值3,就变量初始化后然后会调用类的相应的构造函数,因为我这里没有实现构造函数,所以最后的值就是data的值为0,Node的值为null(引用类型的默认初始化值都是null).

到这里我们已经把类的初始化过程弄的比较清楚了,现在要做的就是如何改变代码使程序异常。我们把注意力放到public Node Next; 这一句上,这里我没有加new Node(),这个方法,所以Next的值为0,现在我们在后面把初始化类的代码加上。就像这样

public class Node
{       
    public int data;
    public Node Next = new Node ...

算法排序之堆排序

Post on by michaelyin

堆排序的重点在于对堆的理解,首先堆是一种数组对象,同时,它也可以被视为一棵完全二叉树,树中的每个节点从上到下,从左到右和数组中的每个元素是一一对应的,二叉树的每一层都是填满的,除了最后一层以外。

比如数组中的第一个元素就是二叉树的根节点,第二个就是元素就是根节点的左边的子节点,而第三个节点就是根节点的右边的子节点,然后第四个节点就是根节点的左边的子节点的左边的子节点,这样以此类推。

通过给定的节点的数组下标,我们可以求出该节点的左边子节点的坐标和右边子节点的坐标。

public static int Left(int parent)
{
    return (2 * parent) + 1;
}

public static int Right(int parent)
{
    return (2 * parent);
}
```csharp

堆有两种,一种是最大堆,一种是最小堆,最大堆的性质就是每个母节点都比它的子节点大,最小堆的性质则相反。我们这里的排序就用最大堆来排序。

Heapify这个方法用来保持最大堆的母节点总是比子节点大这个特性,将数组坐标i和数组输入,它从母节点i处开始比较,如果发现子节点比母节点大,那么就会让母节点下降,下降的母节点还有可能比下面的节点大,所以又进行比较。方法执行完之后,可以保证以i为根节点的子树成为最大堆。关于这个方法有两种实现方式,递归和循环调用,我都写出来了,大家可以都看一下。

```csharp
/// <summary>
/// 保证最大堆的性质,采用递归方法实现
/// </summary>
/// <param name="arrayToSort">< ...