数据结构实践——用Xamarin演示城市列表

单链表实践——城市列表

(多图警告!我放了一大堆类图、截图)

(多废话警告!我不小心在心情不好的时候写了一大堆废话进来)

(多代码警告!我懒得拣关键的代码了,我把整个工程里和题目相关的代码全扔进来了,编辑的时候 Typora 都有点卡了)

题目

UNADJUSTEDNONRAW_thumb_28c8

UNADJUSTEDNONRAW_thumb_28c9

(蒟蒻的抱怨)

“这可太难了呀!”

电脑前的蒟蒻猛地坐直了身子,那双颤巍巍的手像是来自罹患帕金森的老人,几经尝试,才一只抓起了乱扔的抹布,狠狠地擦拭着并不脏的屏幕;另一只揉起了自己的眼睛——蒟蒻相信,这不是幻觉就是屏幕出了问题。

窗体应用呐!又是窗体应用!蒟蒻还记得几个月前自己为了完成要求用 C# 写的窗体小闹钟,关掉了 IDEA、退出了 Xcode,翻越了保护着他生命财产安全的高墙,下载了 dotnet core,安装了 Visual Studio for Mac,开始在 Xamarin 的世界里四处碰壁,碰得鼻青脸肿、碰得头破血流。最后虽然如期把东西做了出来,却落得个128GB的 MacBook 硬盘爆满的下场。

如今伤痛未愈、磁盘未清,又惨遭窗体作业当头一棒!蒟蒻除了怀疑自己的眼睛或屏幕还有其他选择嘛?

“我***不写 C# 了!Swing 过气了么?PyTk 不能用么?Web 开发不香么?”,蒟蒻无声地在内心咆哮着,“iOS 虽然还不熟,但尝试写也没问题!再不济,我还会 Android 开发…”

…(👆一个让人意外的强行转折👇)…

三月的昆明依然迷人。昨天下了雨,今天又是艳阳高照,窗外长了7层楼高的行道树随风欢舞——春风时而和煦、忽又暴躁,谁知道是哪来的力气,它似乎从不疲惫,它不断地把未散尽泥土芳香的甘甜空气送进蒟蒻塞满了纸张、书籍和电子产品的房间。调皮的风元素风儿走时还不忘在蒟蒻的清茶上漾起一个微笑。

“呼——”,一时被这景象吸取了魂魄的蒟蒻这才缓缓回神,看着不知不觉在 Typora 里敲下的这堆文字,一时心里不是滋味。

是啊,最近蒟蒻有些迷茫,不知道该用什么语言、什么框架写作业或是自己的项目了。蒟蒻学的太杂了,每次开发都必须从那么多种技术中挑一个出来用,这时的蒟蒻总是不堪承受抛弃其他语言的痛苦。

“但是没办法,谁让我乐意呢…”

蒟蒻没有办法,只好让上天来决定这一切了。蒟蒻闭上了眼睛,仿佛这样能减轻内心的痛苦。摸起桌上的 D12,蒟蒻的手颤抖地更厉害了,现在是线性马达而不是帕金森了——掷骰子的结果着实让蒟蒻吃了一惊——

是 Xamarin!

不过 Xamarin 就 Xamarin 吧,上天总是对蒟蒻做些奇奇怪怪的事情,蒟蒻已经不相信上帝或任何神灵了。

双眼的焦距在慢慢恢复,手指的颤动像是断了电般骤然止住,在触控板上一划一点,分毫不差,Visual Studio for Mac 在蒟蒻眼前浮现。


(这两天心里颇不宁静…一不小心就写了这么多有的没的,浪费了自己的时间,没有任何意义…)

(生活、梦境、学习中的事都让人头疼,还是写代码让人愉快啊!所以写代码去了,一会儿再接着写这篇文章。)

成果展示

Ok,代码我写好了,回来接着水博客。现在距离写上面那一段东西过去了两天。中间遇到了一些问题严重拖延了进度,最后还是或优雅或笨拙地解决了,一会儿我们会提到。

话不多说,先看成果!

IMG_467

(是的,这个城市链表只是这个 App 里的一个功能!我想把这个 App 写成一个比较全的数据结构与算法演示。)

再看看 Android 中的效果(我设计 UI 的时候是按全面屏来的,我的老 Android 手机屏幕小,效果不太好):

IMG_455

这就是比起 Flutter,我有时更喜欢 Xamarin 的地方,我几乎完全没有自定义布局,得到的 App 在 iOS 上就是遵守 Human Interface Guidelines 的原生 iOS 的感觉,在 Android 上就是符合 Material Design 的谷歌原生的感觉!我用 Mac 不能生成 UWP,不然这套代码还可以生成一个在 Windows 10 上实现 Fluent Design 的微软原生的版本!

而且在这里我还有意外的发现,在 iOS 13 上,Xamarin 生成的 App 自动支持 Dark Mode!只要是没指定颜色的控件,都会自动按照 Apple 的设计准则支持暗色模式。但由于我一开始写了几个 Background="#FAFAFA" 之类的细节颜色指定,就会在暗色中夹杂一块纯白,很丑,我之后再想办法解决。

接下来,我们讨论如何实现这样的一个 Demo App(我们只着重讨论题目部分的东西,也就是“城市链表”点进去的具体 Demo 部分)。

城市列表设计实现

因为我们的目标很明确,就是一个链表放城市,实现增删改查。涉及到的功能也不多,所以设计这个东西不难。我们先从数据结构讲起。

数据结构这一块大体上就是按照上课讲的写。不过按照自己的命名习惯,我修改了一些命名,还有内部的实现也是按照我自己的喜好写的,和老师的稍微有点区别。

线性表

在这个 Demo 里,我们用到了顺序表 SeqList、单链表 SLinkList。这两个东西都实现了线性表接口 ILinearList,提供 InsertRemoveIsEmptyClearSearch 和取下标等操作,具体的类图如下(用软件生成的好像有点错,不管了,以实际代码为准):

LinearList

代码实现(由于文章空间有限,代码我做过一些调整):

线性表接口:

// DataStructureAlgorithm/LinearList/ILinearList.cs

using System;
namespace DataStructureAlgorithm.LinearList
{
   
    public interface ILinearList<T> where T : IComparable<T>
    {
   
        int Length {
    get; }
        T this[int index] {
    get; set; }
        void Insert(int index, T data);
        int Search(T data);
        void RemoveAt(int index);
        bool IsEmpty();
        void Clear();
    }
}

顺序表:

// DataStructureAlgorithm/LinearList/SeqList.cs

using System;
namespace DataStructureAlgorithm.LinearList
{
   
    public class SeqList<T> : ILinearList<T> where T : IComparable<T>
    {
   
        private readonly T[] dataSet;

        public int Length {
    get; private set; }

        public int MaxLength {
    get; }

        public SeqList(int maxLength)
        {
   
            if (maxLength < 0)
            {
   
                throw new ArgumentOutOfRangeException("max Length should >= 0.");
            }
            MaxLength = maxLength;
            dataSet = new T[MaxLength];
            Length = 0;
        }

        public T this[int index]
        {
   
            get
            {
   
                if (index < 0 || index > Length - 1)
                {
   
                    throw new IndexOutOfRangeException();
                }
                return dataSet[index];

            }
            set
            {
   
                if (index < 0 || index > Length - 1)
                {
   
                    throw new IndexOutOfRangeException();
                }
                dataSet[index] = value;
            }
        }

        public void Clear()
        {
   
            Length = 0;
        }

        public void Insert(int index, T data)
        {
   
            if (index < 0 || index > Length)
            {
   
                throw new IndexOutOfRangeException();
            }
            if (Length == MaxLength)
            {
   
                throw new Exception("Failed to Insert: SeqList is already full (Length == MaxLength)");
            }
            for (var i = Length; i > index; i--)
            {
   
                dataSet[i] = dataSet[i - 1];
            }
            dataSet[index] = data;
            Length++;
        }

        public bool IsEmpty()
        {
   
            return (Length == 0);
        }

        public void RemoveAt(int index)
        {
   
            if (index < 0 || index > Length - 1)
            {
   
                throw new IndexOutOfRangeException();
            }
            for (var i = index; i < Length - 1; i++)
            {
   
                dataSet[i] = dataSet[i + 1];
            }
            Length--;
        }

        public int Search(T data)
        {
   
            for (var i = 0; i < Length; i++)
            {
   
                if (data.CompareTo(dataSet[i]) == 0)
                {
   
                    return i;
                }
            }
            return -1;
        }
    }
}

单链表:

// DataStructureAlgorithm/LinearList/SLinkList.cs + SNode.cs

using System;
using System.ComponentModel;

namespace DataStructureAlgorithm.LinearList
{
   
    public class SNode<T> where T : IComparable<T>
    {
   

        public T Data {
    get; set; }
        public SNode<T> Next {
    get; set; }

        public SNode(T data, SNode<T> next)
        {
   
            Data = data;
            Next = (next != null ? next : null);
        }

        public SNode(T data) : this(data, null) {
    }
    }
    
    public class SLinkList<T> : ILinearList<T>, INotifyPropertyChanged where T : IComparable<T>
    {
   
        public int Length {
    get; private set; }

        protected string LengthStr = "Length";

        public SNode<T> HeadNode {
    get; private set; }

        protected string HeadNodeStr = "HeadNode";

        public SLinkList()
        {
   
            Length = 0;
            HeadNode = null;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected SNode<T> NodeAt(int index)
        {
   
            if (index < 0 || index > Length - 1)
            {
   
                throw new IndexOutOfRangeException();
            }

            SNode<T> node = HeadNode;
            for (var i = 0; i < index; i++)
            {
   
                node = node.Next;
            }
            return node;

        }

        public T this[int index]
        {
   
            get
            {
   
                return NodeAt(index).Data;
            }
            set
            {
   
                NodeAt(index).Data = value;
                OnPropertyChanged(IndexerName);
            }
        }

        protected string IndexerName = "this[]";

        public void Clear()
        {
   
            HeadNode = null;
            Length = 0;
        }

        public void Insert(int index, T data)
        {
   
            if (index < 0 || index > Length)
            {
   
                throw new IndexOutOfRangeException();
            }

            SNode<T> current = new SNode
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值