算法(第四版)C# 习题题解——1.2

写在前面

整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp

这一节内容可能会用到的库文件有 Geometry 和 Commercial,同样在 Github 上可以找到。

善用 Ctrl + F 查找题目。

习题 & 题解
练习(1.2.1~1.2.14)
1.2.1
解答

这里自己实现了一个 Point2D 类(包含在了 Geometry 库中)。

JAVA 版本参考:http://algs4.cs.princeton.edu/12oop/Point2D.java.html

求最近两点只需要反复调用 Point2D 类中的 DistTo() 方法就可以了。

代码

Point2D 类

/// <summary>
    /// Point2D 二维点类。
    /// </summary>
    public sealed class Point2D : IComparable<Point2D>
    {
        public readonly static Comparer<Point2D> X_Order = new XOrder();
        public readonly static Comparer<Point2D> Y_Order = new YOrder();
        public readonly static Comparer<Point2D> R_Order = new ROrder();

        public double X { get; }
        public double Y { get; }
        public int Radius { get; set; }

        public Point2D(double x, double y)
        {
            if (double.IsInfinity(x) || double.IsInfinity(y))
            {
                throw new ArgumentException("x, y must be finite");
            }

            if (double.IsNaN(x) || double.IsNaN(y))
            {
                throw new ArgumentNullException("Coordinate cannot be NaN");
            }

            this.X = x;
            this.Y = y;
            this.Radius = 2;
        }

        /// <summary>
        /// 返回极半径。
        /// </summary>
        /// <returns></returns>
        public double R()
        {
            return Math.Sqrt(X * X + Y * Y);
        }

        /// <summary>
        /// 返回极角。
        /// </summary>
        /// <returns></returns>
        public double Theta()
        {
            return Math.Atan2(Y, X);
        }

        /// <summary>
        /// 返回两个点之间的角度。
        /// </summary>
        /// <param name="that">要计算角度的另一个点。</param>
        /// <returns></returns>
        private double AngleTo(Point2D that)
        {
            double dx = that.X - this.X;
            double dy = that.Y - this.Y;
            return Math.Atan2(dy, dx);
        }

        /// <summary>
        /// 判断 a,b,c 三个点的关系,如果 {顺时针, 共线, 逆时针} 则返回 {-1, 0, 1}。
        /// </summary>
        /// <param name="a">第一个点。</param>
        /// <param name="b">第二个点。</param>
        /// <param name="c">第三个点。</param>
        /// <returns></returns>
        public static int CCW(Point2D a, Point2D b, Point2D c)
        {
            double area2 = (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X);
            if (area2 < 0)
                return -1;
            if (area2 > 0)
                return 1;
            return 0;
        }

        /// <summary>
        /// 返回 abc 三个点构成的三角形的面积的平方。
        /// </summary>
        /// <param name="a">第一个点。</param>
        /// <param name="b">第二个点。</param>
        /// <param name="c">第三个点。</param>
        /// <returns></returns>
        public static double Area2(Point2D a, Point2D b, Point2D c)
        {
            return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X);
        }


        /// <summary>
        /// 返回当前点到另一个点之间的距离。
        /// </summary>
        /// <param name="that">另一个点。</param>
        /// <returns></returns>
        public double DistanceTo(Point2D that)
        {
            double dx = this.X - that.X;
            double dy = this.Y - that.Y;

            return Math.Sqrt(dx * dx + dy * dy);
        }

        /// <summary>
        /// 返回当前点到另一个点之间的距离的平方。
        /// </summary>
        /// <param name="that">另一个点。</param>
        /// <returns></returns>
        public double DistanceSquareTo(Point2D that)
        {
            double dx = this.X - that.X;
            double dy = this.Y - that.Y;

            return dx * dx + dy * dy;
        }

        /// <summary>
        /// 绘制二维点。
        /// </summary>
        /// <param name="g">原点在左下方,y轴向上,x轴向右的画布。</param>
        public void Draw(Graphics g)
        {
            g.FillEllipse(Brushes.Black, (int)X, (int)Y, Radius, Radius);
        }

        /// <summary>
        /// 实现 IComparable 接口。
        /// </summary>
        /// <param name="other">需要比较的另一个对象。</param>
        /// <returns></returns>
        public int CompareTo(Point2D other)
        {
            if (this.Y < other.Y)
                return -1;
            if (this.Y > other.Y)
                return 1;
            if (this.X < other.X)
                return -1;
            if (this.X > other.X)
                return 1;

            return 0;
        }

        /// <summary>
        /// 按照 X 顺序比较。
        /// </summary>
        private class XOrder : Comparer<Point2D>
        {
            public override int Compare(Point2D x, Point2D y)
            {
                if (x.X < y.X)
                {
                    return -1;
                }

                if (x.X > y.X)
                {
                    return 1;
                }

                return 0;
            }
        }

        /// <summary>
        /// 按照 Y 顺序比较。
        /// </summary>
        private class YOrder : Comparer<Point2D>
        {
            public override int Compare(Point2D x, Point2D y)
            {
                if (x.Y < y.Y)
                {
                    return -1;
                }
                if (x.Y > y.Y)
                {
                    return 1;
                }

                return 0;
            }
        }

        /// <summary>
        /// 按照极径顺序比较。
        /// </summary>
        private class ROrder : Comparer<Point2D>
        {
            public override int Compare(Point2D x, Point2D y)
            {
                double delta = (x.X * x.X + x.Y * x.Y) - (y.X * y.X + y.Y * y.Y);
                if (delta < 0)
                {
                    return -1;
                }

                if (delta > 0)
                {
                    return 1;
                }

                return 0;
            }
        }

        /// <summary>
        /// 按照 atan2 值顺序比较。
        /// </summary>
        private class Atan2Order : Comparer<Point2D>
        {
            private Point2D parent;
            public Atan2Order() { }
            public Atan2Order(Point2D parent)
            {
                this.parent = parent;
            }
            public override int Compare(Point2D x, Point2D y)
            {
                double angle1 = parent.AngleTo(x);
                double angle2 = parent.AngleTo(y);
                if (angle1 < angle2)
                {
                    return -1;
                }
                else if (angle1 > angle2)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// 按照极角顺序比较。
        /// </summary>
        private class PolorOrder : Comparer<Point2D>
        {
            private Point2D parent;
            public PolorOrder() { }
            public PolorOrder(Point2D parent)
            {
                this.parent = parent;
            }
            public override int Compare(Point2D q1, Point2D q2)
            {
                double dx1 = q1.X - parent.X;
                double dy1 = q1.Y - parent.Y;
                double dx2 = q2.X - parent.X;
                double dy2 = q2.Y - parent.Y;

                if (dy2 >= 0 && dy2 < 0)
                {
                    return -1;
                }
                else if (dy2 >= 0 && dy1 < 0)
                {
                    return 1;
                }
                else if (dy1 == 0 && dy2 == 0)
                {
                    if (dx1 >= 0 && dx2 < 0)
                    {
                        return -1;
                    }
                    else if (dx2 >= 0 && dx1 < 0)
                    {
                        return 1;
                    }
                    else
                    {
                        return 0;
                    }
                }
                else
                {
                    return -CCW(this.parent, q1, q2);
                }
            }
        }

        /// <summary>
        /// 按照距离顺序比较。
        /// </summary>
        private class DistanceToOrder : Comparer<Point2D>
        {
            private Point2D parent;
            public DistanceToOrder() { }
            public DistanceToOrder(Point2D parent)
            {
                this.parent = parent;
            }
            public override int Compare(Point2D p, Point2D q)
            {
                double dist1 = parent.DistanceSquareTo(p);
                double dist2 = parent.DistanceSquareTo(q);

                if (dist1 < dist2)
                {
                    return -1;
                }
                else if (dist1 > dist2)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
        }

        public Comparer<Point2D> Polor_Order()
        {
            return new PolorOrder(this);
        }

        public Comparer<Point2D> Atan2_Order()
        {
            return new Atan2Order(this);
        }

        public Comparer<Point2D> DistanceTo_Order()
        {
            return new DistanceToOrder(this);
        }

        public override bool Equals(object obj)
        {
            if (obj == this)
            {
                return true;
            }
            if (obj == null)
            {
                return false;
            }
            if (obj.GetType() != this.GetType())
            {
                return false;
            }
            Point2D that = (Point2D)obj;
            return this.X == that.X && this.Y == that.Y;
        }

        public override string ToString()
        {
            return "(" + X + ", " + Y + ")";
        }

        public override int GetHashCode()
        {
            int hashX = X.GetHashCode();
            int hashY = Y.GetHashCode();
            return 31 * hashX + hashY;
        }

Main() 方法:

namespace _1._2._1
{
    /*
     * 1.2.1
     * 
     * 编写一个 Point2D 的用例,从命令行接受一个整数 N。
     * 在单位正方形中生成 N 个随机点,然后计算两点之间的最近距离。
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("Type the value of N:");
            int N = int.Parse(Console.ReadLine());
            List<Point2D> pointlist = new List<Point2D>();
            Random random = new Random();

            if (N <= 2)
            {
                Console.WriteLine("Make sure there are 2 points at least");
                return;
            }

            //random.NextDouble() 返回一个 0~1 之间的 double 值
            for (int i = 0; i < N; ++i)
            {
                double x = random.NextDouble();
                double y = random.NextDouble();
                pointlist.Add(new Point2D(x, y));
            }

            double min = pointlist[0].DistanceTo(pointlist[1]);
            for (int i = 0; i < N; ++i)
            {
                for (int j = i + 1; j < N; ++j)
                {
                    double temp = pointlist[i].DistanceTo(pointlist[j]);
                    Console.WriteLine($"Checking Distance({i}, {j}): {temp}");
                    if (temp < min)
                    {
                        min = temp;
                    }
                }
            }

            Console.WriteLine($"\nThe minimal distance is {min}");
        }
    }
}
1.2.2
解答

同样实现了一个 Interval1D 类(位于 Geometry 库)。

JAVA 版本参考:http://algs4.cs.princeton.edu/12oop/Interval1D.java.html

直接调用其中的 Intersect() 方法即可

代码

Interval1D 类:

namespace Geometry
{
    /// <summary>
    /// 一维闭区间。
    /// </summary>
    public class Interval1D
    {
        public static readonly Comparer<Interval1D> Min_Order = new MinEndpointComparer();
        public static readonly Comparer<Interval1D> Max_Order = new MaxEndpointComparer();
        public static readonly Comparer<Interval1D> Length_Order = new LengthComparer();

        public double Min { get; }
        public double Max { get; }

        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="lo">一维区域的下界。</param>
        /// <param name="hi">一维区域的上界。</param>
        public Interval1D(double lo, double hi)
        {
            if (double.IsInfinity(lo) || double.IsInfinity(hi))
            {
                throw new ArgumentException("Endpoints must be finite");
            }
            if (double.IsNaN(lo) || double.IsNaN(hi))
            {
                throw new ArgumentException("Endpoints cannot be NaN");
            }

            if (lo <= hi)
            {
                this.Min = lo;
                this.Max = hi;
            }
            else
            {
                throw new ArgumentException("Illegal interval");
            }
        }

        /// <summary>
        /// 一维区域的长度。
        /// </summary>
        /// <returns>返回长度。</returns>
        public double Length()
        {
            return this.Max - this.Min;
        }

        /// <summary>
        /// 判断目标区间是否被本区间包含。
        /// </summary>
        /// <param name="that">需要判断是否被包含的区间。</param>
        /// <returns></returns>
        public bool Contains(Interval1D that)
        {
            return this.Min < that.Min && this.Max > that.Max;
        }

        /// <summary>
        /// 目标值是否处在区域内。如果目标值在区域内则返回 True,否则返回 False。
        /// </summary>
        /// <param name="x">需要判断的值。</param>
        /// <returns></returns>
        public bool Contains(double x)
        {
            return x >= this.Min && x <= this.Max;
        }

        /// <summary>
        /// 判断两个区域是否相交。
        /// </summary>
        /// <param name="that">需要判断相交的另一个区域。</param>
        /// <returns>如果相交则返回 True,否则返回 False。</returns>
        public bool Intersect(Interval1D that)
        {
            if (this.Max < that.Min || that.Max < this.Min)
                return false;

            return true;
        }

        /// <summary>
        /// 绘制一维区间。
        /// </summary>
        /// <param name="g">原点在左下方,y轴向上,x轴向右的画布。</param>
        /// <param name="y">绘制一维区间的 y轴 坐标。</param>
        public void Draw(Graphics g, int y)
        {
            Point A = new Point((int)Min, y);
            Point B = new Point((int)Max, y);
            g.DrawLine(Pens.Black, A, B);
        }

        /// <summary>
        /// 将区域转换为 string,返回形如 "[lo, hi]" 的字符串。
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string s = "[" + this.Min + ", " + this.Max + "]";
            return s;
        }

        /// <summary>
        /// 判断两个区间是否相等。
        /// </summary>
        /// <param name="obj">相比较的区间。</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj == this)
            {
                return true;
            }
            if (obj == null)
            {
                return false;
            }
            if (obj.GetType() != this.GetType())
            {
                return false;
            }
            Interval1D that = (Interval1D)obj;
            return this.Min == that.Min && this.Max == that.Max;
        }

        /// <summary>
        /// 返回区间的哈希代码。
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            int hash1 = Min.GetHashCode();
            int hash2 = Max.GetHashCode();
            return 31 * hash1 + hash2;
        }

        private class MinEndpointComparer : Comparer<Interval1D>
        {
            public override int Compare(Interval1D a, Interval1D b)
            {
                if (a.Min < b.Min)
                {
                    return -1;
                }
                else if (a.Min > b.Min)
                {
                    return 1;
                }
                else if (a.Max < b.Max)
                {
                    return -1;
                }
                else if (a.Max > b.Max)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
        }

        private class MaxEndpointComparer : Comparer<Interval1D>
        {
            public override int Compare(Interval1D a, Interval1D b)
            {
                if (a.Max < b.Max)
                {
                    return -1;
                }
                else if (a.Max > b.Max)
                {
                    return 1;
                }
                else if (a.Min < b.Min)
                {
                    return -1;
                }
                else if (a.Min > b.Min)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
        }

        private class LengthComparer : Comparer<Interval1D>
        {
            public override int Compare(Interval1D a, Interval1D b)
            {
                double alen = a.Length();
                double blen = b.Length();

                if (alen < blen)
                {
                    return -1;
                }
                else if (alen > blen)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
        }
    }
}

Main() 方法:

namespace _1._2._2
{
    /*
     * 1.2.2
     * 
     * 编写一个 Interval1D 的用例,从命令行接受一个整数 N。
     * 从标准输入中读取 N 个间隔(每个间隔由一对 double 值定义)并打印出所有相交的间隔对。
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Type the value of N:");
            int N = int.Parse(Console.ReadLine());
            List<Interval1D> intervalList = new List<Interval1D>();

            if (N < 2)
            {
                Console.WriteLine("Make sure there are at least 2 Intervals");
                return;
            }

            //读取并建立间隔数组
            Console.WriteLine("Type the data, make sure there is a space between two numbers.\nExample: 0.5 1");
            for (int i = 0; i < N; ++i)
            {
                string temp = Console.ReadLine();
                double lo = double.Parse(temp.Split(' ')[0]);
                double hi = double.Parse(temp.Split(' ')[1]);

                if (lo > hi)
                {
                    double t = lo;
                    lo = hi;
                    hi = t;
                }

                intervalList.Add(new Interval1D(lo, hi));
            }

            //判断是否相交并输出
            for (int i = 0; i < N; ++i)
            {
                for (int j = i + 1; j < N; ++j)
                {
                    if (intervalList[i].Intersect(intervalList[j]))
                    {
                        Console.WriteLine($"{intervalList[i].ToString()} {intervalList[j].ToString()}");
                    }
                }
            }
        }
    }
}
 
1.2.3
解答

首先先实现一个 Interval2D 类(位于 Geometry 库),再使用窗体应用程序绘图。

JAVA 版本参考:http://algs4.cs.princeton.edu/12oop/Interval2D.java.html

代码

Interval2D:

using System.Drawing;

namespace Geometry
{
    /// <summary>
    /// 二维闭合区间。
    /// </summary>
    public class Interval2D
    {
        private readonly Interval1D X;
        private readonly Interval1D Y;

        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="x">x 轴上的范围。</param>
        /// <param name="y">y 轴上的范围。</param>
        public Interval2D(Interval1D x, Interval1D y)
        {
            this.X = x;
            this.Y = y;
        }

        /// <summary>
        /// 判断两个平面是否相交。
        /// </summary>
        /// <param name="that">需要判断的另一个平面。</param>
        /// <returns></returns>
        public bool Intersects(Interval2D that)
        {
            if (!this.X.Intersect(that.X))
            {
                return false;
            }

            if (!this.Y.Intersect(that.Y))
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 判断目标区间是否被本区间包含。
        /// </summary>
        /// <param name="that">需要判断是否被包含的区间。</param>
        /// <returns></returns>
        public bool Contains(Interval2D that)
        {
            return this.X.Contains(that.X) && this.Y.Contains(that.Y);
        }

        /// <summary>
        /// 判断一个二维点是否在该平面范围内。
        /// </summary>
        /// <param name="p">需要判断的二维点。</param>
        /// <returns></returns>
        public bool Contains(Point2D p)
        {
            return (this.X.Contains(p.X) && this.Y.Contains(p.Y));
        }

        /// <summary>
        /// 计算平面范围的面积。
        /// </summary>
        /// <returns></returns>
        public double Area()
        {
            return this.X.Length() * this.Y.Length();
        }

        /// <summary>
        /// 在画布上绘制二维区间。
        /// </summary>
        /// <param name="g">原点在左下方,x轴向右,y轴向上的画布。</param>
        public void Draw(Graphics g)
        {
            Rectangle rect = new Rectangle((int)this.X.Min, (int)this.Y.Min, (int)this.X.Length(), (int)this.Y.Length());
            g.DrawRectangle(Pens.White, rect);
            g.FillRectangle(Brushes.Black, rect);
        }

        /// <summary>
        /// 返回形如“[xmin, xmax] x [ymin, ymax]”的字符串。
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return X + "x" + Y;
        }

        /// <summary>
        /// 判断两个二维区间是否相等。
        /// </summary>
        /// <param name="obj">需要比较的另一个区间。</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj == this)
            {
                return true;
            }
            if (obj  == null)
            {
                return false;
            }

            if (obj.GetType() != this.GetType())
            {
                return false;
            }

            Interval2D that = (Interval2D)obj;

            return this.X.Equals(that.X) && this.Y.Equals(that.Y);
        }

        /// <summary>
        /// 获取哈希值
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            int hash1 = this.X.GetHashCode();
            int hash2 = this.Y.GetHashCode();

            return 31 * hash1 + hash2;
        }
    }
}

绘图方法:

/// <summary>
        /// 主绘图函数。
        /// </summary>
        /// <param name="N">2D 间隔的数目。</param>
        /// <param name="Min">分布范围的下界。(大于 0 且小于 1)</param>
        /// <param name="Max">分布范围的上界。(大于 0 且小于 1)</param>
        public static void StartDrawing(int N, double Min, double Max)
        {
            Interval2D[] list = new Interval2D[N];
            Random random = new Random();

            //开始绘图
            Form2 drawPad = new Form2();
            drawPad.Show();
            Graphics graphics = drawPad.CreateGraphics();

            //生成随机二维间隔
            for (int i = 0; i < N; ++i)
            {
                double x = random.NextDouble() * (Max - Min) + Min;
                double y = random.NextDouble() * (Max - Min) + Min;
                if (x >= y)
                {
                    double temp = x;
                    x = y;
                    y = temp;
                }
                x *= drawPad.ClientRectangle.Width;
                y *= drawPad.ClientRectangle.Width;
                Interval1D tempx = new Interval1D(x, y);

                x = random.NextDouble() * (Max - Min) + Min;
                y = random.NextDouble() * (Max - Min) + Min;
                if (x >= y)
                {
                    double temp = x;
                    x = y;
                    y = temp;
                }
                x *= drawPad.ClientRectangle.Height;
                y *= drawPad.ClientRectangle.Height;
                Interval1D tempy = new Interval1D(x, y);

                list[i] = new Interval2D(tempx, tempy);
            }

            //计算相交和包含的数量
            int intersectNum = 0;
            for (int i = 0; i < N; ++i)
            {
                for (int j = i + 1; j < N; ++j)
                {
                    if (list[i].Intersects(list[j]))
                    {
                        intersectNum++;
                    }
                }
            }

            int containsNum = 0;
            for (int i = 0; i < N; ++i)
            {
                for (int j = 0; j < N; ++j)
                {
                    if (i == j)
                        continue;

                    if (list[i].Contains(list[j]))
                    {
                        containsNum++;
                    }
                }
            }

            //移动原点至左下方,翻转坐标系
            graphics.TranslateTransform(0, drawPad.ClientRectangle.Height);
            graphics.ScaleTransform(1, -1);

            //绘制所有区间
            foreach (Interval2D n in list)
            {
                n.Draw(graphics);
            }

            //新建一个窗口,显示计算结果
            MessageBox.Show($"相交的区间数:{intersectNum}, 包含的区间数:{containsNum}");

            //清理资源
            graphics.Dispose();
        }
1.2.4
解答

在 C# 中,这段代码能够完成交换的工作,输出为:

world
hello
代码
using System;

namespace _1._2._4
{
    /*
     * 1.2.4
     * 
     * 以下这段代码会打印出什么?
     * String string1 = "hello";
     * String string2 = string1;
     * string1 = "world";
     * StdOut.println(string1);
     * StdOut.println(string2);
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            string string1 = "hello";
            string string2 = string1;
            string1 = "world";
            Console.WriteLine(string1);
            Console.WriteLine(string2);
        }
    }
}
1.2.5
解答

string 类型中的 Uppercase() 以及 Substring() 都不会改变原有字符串,而是新建一个字符串。因此输出仍然为 Hello World。

代码
using System;

namespace _1._2._5
{
    /*
     * 1.2.5
     * 
     * 以下这段代码会打印出什么?
     * String s = "Hello World";
     * s.toUpperCase();
     * s.substring(6, 11);
     * StdOut.println(s);
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            string s = "Hello World";
            s.ToUpper();
            s.Substring(6, 5);//C# 中两个参数分别代表子串起始下标和长度
            Console.WriteLine(s);
        }
    }
}
1.2.6
解答

对于任意字符串 s,将其拆分成 s = s1 + s2(s2长度即为循环移动的位数)
其回环变位则为 s' = s2 + s1
显然 s' + s' = s2 + s1 + s2 + s1
即 s' + s' = s2 + s + s1,其中必定包含 s
例如 ABC 和 BCA, BCABCA 显然包含 ABC

代码
using System;

namespace _1._2._6
{
    /*
     * 1.2.6
     * 
     * 如果字符串 s 中的字符循环移动任意位置之后能够得到另一个字符串 t,
     * 那么 s 就被称为 t 的回环变位(circular rotation)。
     * 例如,ACTGACG 就是 TGACGAC 的一个回环变位,反之亦然。
     * 判定这个条件在基因组序列的研究中是很重要的。
     * 编写一个程序检查两个给定的字符串 s 和 t 是否互为回环变位。
     * 提示:答案只需要一行用到 indexOf()、length() 和字符串连接的代码。
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            string s1 = "ACTGACG";
            string s2 = "TGACGAC";

            Console.WriteLine(Circular(s1, s2));
        }


        //对于任意字符串 s,将其拆分成 s = s1 + s2(s2长度即为循环移动的位数)
        //其回环变位则为 s' = s2 + s1
        //显然 s' + s' = s2 + s1 + s2 + s1
        //即 s' + s' = s2 + s + s1,其中必定包含 s
        //例如 ABC 和 BCA, BCABCA 显然包含 ABC
        static bool Circular(string s1, string s2)
        {
            return s1.Length == s2.Length && (s2 + s2).Contains(s1);
        }
    }
}
1.2.7
解答

递归交换字符顺序,最后返回反序的字符串。

Mystery(ABCD)=

Mystery(CD) + Mystery(AB)=

Mystery(D) + Mystery(C) + Mystery(B) + Mystery(A)=

DCBA

代码
using System;

namespace _1._2._7
{
    /*
     * 1.2.7
     * 
     * 以下递归函数的返回值是什么?
     * public static String mystery(String s)
     * {
     *      int N = s.length();
     *      if (N <= 1) return s;
     *      String a = s.substring(0, N/2);
     *      String b = s.substring(N/2, N);
     *      return mystery(b) + mystery(a);
     * }
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Mystery("Hello1"));
        }

        /// <summary>
        /// 输出反向字符串。
        /// </summary>
        /// <param name="s">原字符串。</param>
        /// <returns></returns>
        public static string Mystery(string s)
        {
            int N = s.Length;
            if (N <= 1)
                return s;
            string a = s.Substring(0, N / 2);
            string b = s.Substring(N / 2, N - N / 2);

            return Mystery(b) + Mystery(a);
        }
    }
}
1.2.8
解答

作用就是交换两个数组。

但在 C# 或 JAVA 中,数组变量实际是数组的一个引用(类似于指针),交换两个引用的效率与数组大小无关,都是常数时间的。

image

代码
using System;
using System.IO;

namespace _1._2._8
{
    /*
     * 1.2.8
     * 
     * 设 a[] 和 b[] 均为长数百万的整型数组。以下代码的作用是什么?有效吗?
     * int[] t = a; a = b; b = t;
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            //读取 largeW.txt
            string[] allNums = File.ReadAllLines("largeW.txt");
            int N = allNums.Length;
            int[] a = new int[N];
            int[] b = new int[N];

            //数组 a 与数组 b 数字顺序相反
            for (int i = 0; i < N; ++i)
            {
                a[i] = int.Parse(allNums[i]);
                b[N - i - 1] = a[i];
            }

            //输出前5个数字
            Console.WriteLine("Before Swap");
            Console.Write("a:");
            for (int i = 0; i < 5; ++i)
            {
                Console.Write($" {a[i]}");
            }
            Console.WriteLine();
            Console.Write("b:");
            for (int i = 0; i < 5; ++i)
            {
                Console.Write($" {b[i]}");
            }
            Console.WriteLine();

            //交换
            int[] t = a;
            a = b;
            b = t;

            //再次输出
            Console.WriteLine("After Swap");
            Console.Write("a:");
            for (int i = 0; i < 5; ++i)
            {
                Console.Write($" {a[i]}");
            }
            Console.WriteLine();
            Console.Write("b:");
            for (int i = 0; i < 5; ++i)
            {
                Console.Write($" {b[i]}");
            }
            Console.WriteLine();
        }
    }
}
1.2.9
解答

首先实现一个 Counter 类,随后使用非递归版本的 BinarySearch,每进行一次 While 循环就让 Counter 加一。

代码

Counter 类:

namespace _1._2._9
{
    /// <summary>
    /// 计数器类
    /// </summary>
    class Counter
    {
        private readonly string name;
        private int count;

        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="id">计数器的名称。</param>
        public Counter(string id)
        {
            this.name = id;
        }

        /// <summary>
        /// 计数器加一。
        /// </summary>
        public void Increment()
        {
            count++;
        }

        /// <summary>
        /// 获取当前计数值。
        /// </summary>
        /// <returns></returns>
        public int Tally()
        {
            return count;
        }

        /// <summary>
        /// 输出形如 “1 counter” 的字符串。
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return count + " " + name;
        }
    }
}

Main():

using System;
using System.IO;

namespace _1._2._9
{
    /*
     * 1.2.9
     * 
     * 修改 BinarySearch(请见 1.1.10.1 节中的二分查找代码),
     * 使用 Counter 统计在有查找中被检查的键的总数并在查找全部结束后打印该值。
     * 提示:在 main() 中创建一个 Counter 对象并将它作为参数传递给 rank()
     * 
     */
    class Program
    {
        //参考 1.1.10 节的代码
        static void Main(string[] args)
        {
            Counter count = new Counter("BinarySearch");

            //读取白名单
            string[] whiteListString = File.ReadAllLines("tinyW.txt");
            int[] whiteList = new int[whiteListString.Length];
            
            for (int i = 0; i < whiteListString.Length; ++i)
            {
                whiteList[i] = int.Parse(whiteListString[i]);
            }
            Array.Sort(whiteList);

            //读取查询值
            string[] inputListString = File.ReadAllLines("tinyT.txt");
            int[] inputList = new int[inputListString.Length];

            for (int i = 0; i < inputListString.Length; ++i)
            {
                inputList[i] = int.Parse(inputListString[i]);
            }

            //对每一个查询值进行二分查找
            foreach (int n in inputList)
            {
                int result = rank(n, whiteList, count);
                //将不在白名单上的数据输出
                if (result == -1)
                {
                    Console.WriteLine(n);
                }
            }
            Console.WriteLine();

            //输出查询数目
            Console.WriteLine(count.Tally());
        }

        static int rank(int key, int[] a, Counter count)
        {
            int lo = 0;
            int hi = a.Length - 1;
            while (lo <= hi)
            {
                int mid = lo + (hi - lo) / 2;
                count.Increment();
                if (key < a[mid])
                {
                    hi = mid - 1;
                }
                else if (key > a[mid])
                {
                    lo = mid + 1;
                }
                else
                {
                    return mid;
                }
            }
            return -1;
        }
    }
}
1.2.10
解答

在 Counter 类基础上修改即可。

image

代码

VisualCounter 类:

using System.Drawing;

namespace _1._2._10
{
    /// <summary>
    /// 可视化计数器
    /// </summary>
    class VisualCounter
    {
        private readonly string name;
        private int count;
        private int max;
        private int operatorTimes;

        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="id">计数器的名称。</param>
        /// <param name="max">计数器的最大值。</param>
        /// <param name="operatorTimes">计数器的最大操作数。</param>
        public VisualCounter(string id, int max, int operatorTimes)
        {
            this.name = id;
            this.max = max;
            this.operatorTimes = operatorTimes;
        }

        /// <summary>
        /// 计数器加一。
        /// </summary>
        public bool Increment()
        {
            if (operatorTimes <= 0)
                return false;
            if (count < max)
            {
                count++;
                operatorTimes--;
            }
            return true;
        }

        /// <summary>
        /// 计数器减一。
        /// </summary>
        public bool Decreasement()
        {
            if (operatorTimes <= 0)
                return false;
            if (count > 0)
            {
                count--;
                operatorTimes--;
            }
            return true;
        }

        /// <summary>
        /// 获取当前计数值。
        /// </summary>
        /// <returns></returns>
        public int Tally()
        {
            return count;
        }

        /// <summary>
        /// 输出形如 “1 counter” 的字符串。
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return count + " " + name;
        }

        /// <summary>
        /// 绘制计数器的图形。
        /// </summary>
        /// <param name="g">画布。</param>
        /// <param name="width">绘图区宽度。</param>
        /// <param name="height">绘图区高度。</param>
        /// <param name="font">显示的字体。</param>
        public void Draw(Graphics g, int width, int height, Font font)
        {
            //清空画布
            g.Clear(SystemColors.Control);
            //将画布分为上 1/3 和下 2/3
            RectangleF headPart = new RectangleF(0, 0, width, height / 3);
            Rectangle bodyPart = new Rectangle(0, height / 3, (height * 2) / 3, (height * 2) / 3);

            //绘图
            g.DrawString($"计数:{count} 剩余操作数:{operatorTimes} 最大值:{max}", font, Brushes.Black, headPart);
            g.FillPie(Brushes.Blue, bodyPart, 0, 360 * (float)count / max);
        }
    }
}

Form2(绘图窗口):

using System;
using System.Drawing;
using System.Windows.Forms;

namespace _1._2._10
{
    public partial class Form2 : Form
    {
        VisualCounter counter;
        Graphics graphics;
        public Form2(int N, int max)
        {
            InitializeComponent();
            counter = new VisualCounter("count", max, N);
            graphics = this.PaintArea.CreateGraphics();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!counter.Increment())
            {
                this.ErrorLabel.Text = "操作数不足";
            }
            else
            {
                this.ErrorLabel.Text = "";
                counter.Draw(graphics,this.PaintArea.Width, this.PaintArea.Height, this.Font);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (!counter.Decreasement())
            {
                this.ErrorLabel.Text = "操作数不足";
            }
            else
            {
                this.ErrorLabel.Text = "";
                counter.Draw(graphics, this.PaintArea.Width, this.PaintArea.Height, this.Font);
            }
        }
    }
}

 

1.2.11
解答

在构造函数开始时做一次判断,非法时抛出异常。

首先建立一个数组,数组的第 1 项至第 12 项的值就是每个月的天数。

再声明一个布尔类型的变量,用于标记是否是闰年。

代码
using System;

namespace _1._2._11
{
    class SmartDate
    {
        public int Month { get; }//
        public int Day { get; }//
        public int Year { get; }////每个月对应的天数,第 0 位空出来
        static private int[] dayOfMonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

        public SmartDate(int m, int d, int y)
        {
            if (Vaildation(m, d, y) == false)
                throw new FormatException("Invaild Date");
            this.Month = m;
            this.Day = d;
            this.Year = y;
        }

        private bool Vaildation(int m, int d, int y)
        {
            if (y < 0)
                return false;

            bool isLeapYear = false;

            if (m > 12 || m < 1)
                return false;
            if (d < 0)
                return false;
            if (m == 2 && d > 29 && isLeapYear)
                return false;
            if (d > dayOfMonth[m])
                return false;

            return true;
        }

        private bool IsLeapYear(int y)
        {
            if (y % 400 == 0)
                return true;
            if (y % 100 != 0 && y % 4 == 0)
                return true;

            return false;
        }

        public override string ToString()
        {
            return this.Month + "/" + this.Day + "/" + this.Year;
        }
    }
}
1.2.12
解答

这里使用蔡勒公式来推算星期。

参考:http://www.cnblogs.com/mq0036/p/3534314.html

代码
/// <summary>
        /// 计算当前日期是星期几,返回对应的星期名称。
        /// </summary>
        /// <returns></returns>
        public string DayOfTheWeek()
        {
            int d = this.Day;
            int m = this.Month;
            int y = this.Year;
            
            if (m < 3)
            {
                m += 12;
                y--;
            }

            //使用蔡勒公式计算,参见 http://www.cnblogs.com/mq0036/p/3534314.html
            int w = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;

            return dayOfWeek[w];
        }
1.2.13
解答

直接实现即可。

JAVA 版本可以参考:http://algs4.cs.princeton.edu/12oop/Transaction.java.html

代码
using System;
using System.Collections.Generic;

namespace Commercial
{
    public class Transaction : IComparable<Transaction>
    {
        public string Who { get; }
        public Date When { get; }
        public double Amount { get; }

        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="transaction">用空格隔开的形如 “姓名 日期 金额” 的字符串。</param>
        public Transaction(string transaction)
        {
            string[] a = transaction.Split(' ');
            Who = a[0];
            When = new Date(a[1]);
            Amount = double.Parse(a[2]);
        }

        /// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="who">客户姓名。</param>
        /// <param name="when">交易日期。</param>
        /// <param name="amount">交易金额。</param>
        public Transaction(string who, Date when, double amount)
        {
            if (double.IsNaN(amount) || double.IsInfinity(amount))
            {
                throw new ArgumentException("Amount cannot be NaN or Infinity");
            }
            this.Who = who;
            this.When = when;
            this.Amount = amount;
        }

        /// <summary>
        /// 返回字符串形式的交易信息。
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("{0, -10} {1, 10} {2, 8:F2}", Who, When, Amount);
        }

        /// <summary>
        /// 默认按照交易金额升序比较。
        /// </summary>
        /// <param name="other">比较的另一个对象。</param>
        /// <returns></returns>
        public int CompareTo(Transaction other)
        {
            if (this.Amount < other.Amount)
                return -1;
            if (this.Amount > other.Amount)
                return 1;
            return 0;
        }

        /// <summary>
        /// 按照客户姓名升序比较。
        /// </summary>
        public class WhoOrder : IComparer<Transaction>
        {
            int IComparer<Transaction>.Compare(Transaction x, Transaction y)
            {
                return x.Who.CompareTo(y.Who);
            }
        }

        /// <summary>
        /// 按照交易时间升序比较。
        /// </summary>
        public class WhenOrder : IComparer<Transaction>
        {
            int IComparer<Transaction>.Compare(Transaction x, Transaction y)
            {
                return x.When.CompareTo(y.When);
            }
        }

        /// <summary>
        /// 按照交易金额升序比较。
        /// </summary>
        public class HowMuchOrder : IComparer<Transaction>
        {
            int IComparer<Transaction>.Compare(Transaction x, Transaction y)
            {
                return x.Amount.CompareTo(y.Amount);
            }
        }

        /// <summary>
        /// 比较两笔交易是否相同。
        /// </summary>
        /// <param name="obj">另一个对象。</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj == this)
                return true;
            if (obj == null)
                return false;
            if (obj.GetType() != this.GetType())
                return false;
            Transaction that = (Transaction)obj;

            return
                (that.Amount == this.Amount) &&
                (that.When.Equals(this.When)) &&
                (that.Who == this.Who);
        }

        /// <summary>
        /// 返回交易信息的哈希值。
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            int hash = 1;
            hash = 31 * hash + Who.GetHashCode();
            hash = 31 * hash + When.GetHashCode();
            hash = 31 * hash + Amount.GetHashCode();
            return hash;
        }
    }
}
1.2.14
解答

上一题中的代码已经包含了对 Equals() 方法的实现。

代码
/// <summary>
        /// 比较两笔交易是否相同。
        /// </summary>
        /// <param name="obj">另一个对象。</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj == this)
                return true;
            if (obj == null)
                return false;
            if (obj.GetType() != this.GetType())
                return false;
            Transaction that = (Transaction)obj;

            return
                (that.Amount == this.Amount) &&
                (that.When.Equals(this.When)) &&
                (that.Who == this.Who);
        }
提高题(1.2.15~1.2.19)
1.2.15
解答

这里我们基于 File.ReadAllLines() 进行实现。

代码
public static int[] ReadInts(string path)
        {
            string[] allLines = File.ReadAllLines(path);
            int[] result = new int[allLines.Length];
            
            for (int i = 0; i < allLines.Length; ++i)
            {
                result[i] = int.Parse(allLines[i]);
            }

            return result;
        }
1.2.16
解答

JAVA 版本参考:http://algs4.cs.princeton.edu/12oop/Rational.java.html

欧几里得算法仅适用于正整数,使用前需要注意。

用欧几里得算法找到公因子之后直接化简即可。

代码
using System;

namespace _1._2._16
{
    public class Rational
    {
        public long Numerator { get; }
        public long Denominator { get; }
        private bool isNagative;

        /// <summary>
        /// 构造一个有理数对象,自动变为最简形式。
        /// </summary>
        /// <param name="numerator">分子。</param>
        /// <param name="denominator">分母。</param>
        /// <exception cref="ArgumentException">分母为 0 时抛出</exception>
        public Rational(long numerator, long denominator)
        {
            if (denominator == 0)
                throw new ArgumentException("Denominator cannot be 0");

            if (numerator < 0 && denominator < 0)
            {
                isNagative = false;
                numerator = -numerator;
                denominator = -denominator;
            }
            else if (numerator < 0 || denominator < 0)
            {
                isNagative = true;
            }
            else
            {
                isNagative = false;
            }

            long gcd = GCD(Math.Abs(numerator), Math.Abs(denominator));
            if (gcd != 1)
            {
                numerator /= gcd;
                denominator /= gcd;
            }
            this.Numerator = numerator;
            this.Denominator = denominator;
        }

        /// <summary>
        /// 将两个有理数对象相加,返回一个有理数。
        /// </summary>
        /// <param name="b">加数。</param>
        /// <returns></returns>
        public Rational Plus(Rational b)
        {
            Rational result = new Rational(this.Numerator * b.Denominator + b.Numerator * this.Denominator, this.Denominator * b.Denominator);
            return result;
        }

        /// <summary>
        /// 以当前对象为被减数,减去一个有理数。
        /// </summary>
        /// <param name="b">减数。</param>
        /// <returns></returns>
        public Rational Minus(Rational b)
        {
            Rational result = new Rational(this.Numerator * b.Denominator - b.Numerator * this.Denominator, this.Denominator * b.Denominator);
            return result;
        }

        /// <summary>
        /// 将两个有理数对象相乘。
        /// </summary>
        /// <param name="b">乘数。</param>
        /// <returns></returns>
        public Rational Multiply(Rational b)
        {
            Rational result = new Rational(this.Numerator * b.Numerator, this.Denominator * b.Denominator);
            return result;
        }

        /// <summary>
        /// 以当前有理数为被除数,除以一个有理数。
        /// </summary>
        /// <param name="b">除数。</param>
        /// <returns></returns>
        public Rational Divide(Rational b)
        {
            Rational result = new Rational(this.Numerator * b.Denominator, this.Denominator * b.Numerator);
            return result;
        }

        /// <summary>
        /// 求两个正整数的最大公约数。
        /// </summary>
        /// <param name="a">第一个整数。</param>
        /// <param name="b">第二个整数。</param>
        /// <returns></returns>
        private long GCD(long a, long b)
        {
            if (b == 0)
                return a;
            return GCD(b, a % b);
        }

        public override bool Equals(object obj)
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (obj.GetType() != this.GetType())
                return false;

            Rational that = (Rational)obj;
            return (this.Numerator == that.Numerator) && (this.Denominator == that.Denominator);
        }

        public override int GetHashCode()
        {
            return 31 * this.Numerator.GetHashCode() + this.Denominator.GetHashCode();
        }

        /// <summary>
        /// 返回形如 “分子/分母” 的字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string result = "";
            if (isNagative)
                result += "-";
            result += Math.Abs(this.Numerator) + "/" + Math.Abs(this.Denominator);
            return result;
        }
    }
}
1.2.17
解答

在 C# 中使用 checked 关键字包裹整数运算的代码即可自动检查溢出。

在 JAVA 中可以考虑在运算前控制运算数的大小。

例如 a + b 之前保证 long.MaxValue – b >= a 等等。

代码
using System;

namespace _1._2._17
{
    public class Rational
    {
        public long Numerator { get; }
        public long Denominator { get; }
        private bool isNagative;

        /// <summary>
        /// 构造一个有理数对象,自动变为最简形式。
        /// </summary>
        /// <param name="numerator">分子。</param>
        /// <param name="denominator">分母。</param>
        /// <exception cref="ArgumentException">分母为 0 时抛出</exception>
        public Rational(long numerator, long denominator)
        {
            if (denominator == 0)
                throw new ArgumentException("Denominator cannot be 0");

            if (numerator < 0 && denominator < 0)
            {
                isNagative = false;
                numerator = -numerator;
                denominator = -denominator;
            }
            else if (numerator < 0 || denominator < 0)
            {
                isNagative = true;
            }
            else
            {
                isNagative = false;
            }

            long gcd = GCD(Math.Abs(numerator), Math.Abs(denominator));
            if (gcd != 1)
            {
                numerator /= gcd;
                denominator /= gcd;
            }
            this.Numerator = numerator;
            this.Denominator = denominator;
        }

        /// <summary>
        /// 将两个有理数对象相加,返回一个有理数。
        /// </summary>
        /// <param name="b">加数。</param>
        /// <returns></returns>
        public Rational Plus(Rational b)
        {
            checked
            {
                Rational result = new Rational(this.Numerator * b.Denominator + b.Numerator * this.Denominator, this.Denominator * b.Denominator);
                return result;
            }
        }

        /// <summary>
        /// 以当前对象为被减数,减去一个有理数。
        /// </summary>
        /// <param name="b">减数。</param>
        /// <returns></returns>
        public Rational Minus(Rational b)
        {
            checked
            {
                Rational result = new Rational(this.Numerator * b.Denominator - b.Numerator * this.Denominator, this.Denominator * b.Denominator);
                return result;
            }
        }

        /// <summary>
        /// 将两个有理数对象相乘。
        /// </summary>
        /// <param name="b">乘数。</param>
        /// <returns></returns>
        public Rational Multiply(Rational b)
        {
            checked
            {
                Rational result = new Rational(this.Numerator * b.Numerator, this.Denominator * b.Denominator);
                return result;
            }
        }

        /// <summary>
        /// 以当前有理数为被除数,除以一个有理数。
        /// </summary>
        /// <param name="b">除数。</param>
        /// <returns></returns>
        public Rational Divide(Rational b)
        {
            checked
            {
                Rational result = new Rational(this.Numerator * b.Denominator, this.Denominator * b.Numerator);
                return result;
            }
        }

        /// <summary>
        /// 求两个正整数的最大公约数。
        /// </summary>
        /// <param name="a">第一个整数。</param>
        /// <param name="b">第二个整数。</param>
        /// <returns></returns>
        private long GCD(long a, long b)
        {
            if (b == 0)
                return a;
            return GCD(b, a % b);
        }

        public override bool Equals(object obj)
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (obj.GetType() != this.GetType())
                return false;

            Rational that = (Rational)obj;
            return (this.Numerator == that.Numerator) && (this.Denominator == that.Denominator);
        }

        public override int GetHashCode()
        {
            return 31 * this.Numerator.GetHashCode() + this.Denominator.GetHashCode();
        }

        /// <summary>
        /// 返回形如 “分子/分母” 的字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string result = "";
            if (isNagative)
                result += "-";
            result += Math.Abs(this.Numerator) + "/" + Math.Abs(this.Denominator);
            return result;
        }
    }
}
1.2.18
解答

当数据比较大时—— 例如 10^9 加上随机小数组成的数列,这时 double 的小数精度将受限。
求和之后整数部分更大,小数部分将自动四舍五入,出现误差
这时再计算平均值时将会带来较大的误差。
因此采用另一个递推公式:
k 为下标。
Mk = Mk-1+ (xk – Mk-1)/k
Sk = Sk-1 + (xk – Mk-1)*(xk – Mk).
方差 s^2 = Sk/(k – 1).
这种情况下并没有直接对所有输入值求和,小数精度不会过多受到整数部分长度的影响。

有关这两个公式的证明可以参考这篇论文,或者去查看我的知乎回答

代码
using System;

namespace _1._2._18
{
    public class Accumulator
    {
        private double m;
        private double s;
        private int N;

        public void AddDataValue(double x)
        {
            N++;
            s = s + 1.0 * (N - 1) / N * (x - m) * (x - m);
            m = m + (x - m) / N;
        }
        public double Mean()
        {
            return m;
        }
        public double Var()
        {
            return s / (N - 1);
        }
        public double Stddev()
        {
            return Math.Sqrt(this.Var());
        }
        public override string ToString()
        {
            return "Mean (" + N + " values): " + string.Format("{0, 7:F5}", Mean());
        }
    }
}
1.2.19
解答

之前的 Date 和 Transaction 已经包含了这些实现。

代码

Date:

/// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="date">形如 "05/31/2017" 的字符串。</param>
        public Date(string date)
        {
            string[] a = date.Split('/');
            if (a.Length != 3)
                throw new ArgumentException("Illgal Date");
            Month = int.Parse(a[0]);
            Day = int.Parse(a[1]);
            Year = int.Parse(a[2]);
        }

Transaction:

/// <summary>
        /// 构造函数。
        /// </summary>
        /// <param name="transaction">用空格隔开的形如 “姓名 日期 金额” 的字符串。</param>
        public Transaction(string transaction)
        {
            string[] a = transaction.Split(' ');
            Who = a[0];
            When = new Date(a[1]);
            Amount = double.Parse(a[2]);
        }
posted @ 2017-06-27 20:25  沈星繁  阅读(1442)  评论(0编辑  收藏  举报