额外作业 - 单链表窗体应用操作

  • 线性表接口定义,将有关线性表的操作封装到interface接口中,同时在实现Search时为了使自定义数据类型能够使用该接口,需要对T类型进行一个约束限定条件,即进去的T类型要实现IComparable这样一个接口,如果实现的话这个数据类型就可被使用:
namespace Experiment_1
{
    public interface ILinearList<T> where T : IComparable<T>
    {
        int Length { get; }
        T this[int index] { get; set; }
        void Clear();
        bool IsEmpty();
        void Insert(int index, T data);
        void Remove(int index);
        int Search(T data);
    }
}
  • 顺序表定义,用顺序存储结构实现上述接口(即写在接口中的线性表),在顺序表中实现接口的方法(若要实现接口,而必须实现接口中定义的所有属性和方法):
namespace Experiment_1
{
	//实现两个接口
    public class SeqList<T> : ILinearList<T> where T : IComparable<T>
    {
    	//线性表的核心是数组
        private T[] _dataset;
        //照应SeqList(int max),作为属性展示数组规模,开辟空间
        private int _maxSize;
        private int _length;

        public int Length
        {
            get
            {
                return _length;
            }
        }
        public int MaxSize
        {
            get
            {
                return _maxSize;
            }
        }

		//在一开始确定数组能容纳的最大元素数
        public SeqList(int max)
        {
            if (max <= 0)
                throw new ArgumentOutOfRangeException();

            _maxSize = max;
            _length = 0;
            _dataset = new T[_maxSize];//给数组开一块存储空间
        }

		//索引器
        public T this[int index]
        {
            get
            {
                if (index < 0 || index > _length - 1)
                    throw new ArgumentOutOfRangeException();

                return _dataset[index];
            }
            set
            {
                if (index < 0 || index > _length - 1)
                    throw new ArgumentOutOfRangeException();

                _dataset[index] = value;
            }
        }

        public void Clear()
        {
            _length = 0;
        }

        public void Insert(int index, T data)
        {
            if (index < 0 || index > _length)
                throw new ArgumentOutOfRangeException();
            if (_length == _maxSize)
                throw new Exception("顺序表已满");
			//将所插位置后面的元素全部后移
            for (int i = _length; i > index; i--)
            {
                _dataset[i] = _dataset[i - 1];
            }
            _dataset[index] = data;
            _length++;
        }

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

        public void Remove(int index)
        {
            if (index < 0 || index > _length - 1)
                throw new ArgumentOutOfRangeException();

			//循环将索引位置元素覆盖掉
            for (int i = index; i < _length - 1; i++)
            {
                _dataset[i] = _dataset[i + 1];
            }
            _length--;
        }

        public int Search(T data)
        {
            int i;
            for (i = 0; i < _length; i++)
            {
            	//因使用IComparable接口,所以比较的话须使用CompareTo()方法
                if (_dataset[i].CompareTo(data) == 0)
                    break;
            }
            return i == _length ? -1 : i;
        }
    }
}

(如果以上是在另一个项目类库中编写的,在使用的时候还需引用该类库,同时开头声明using+命名空间)

  • 单链表结点的定义:
namespace Experiment_1
{
	//由于单链表也要实现上述接口,所以也要加IComparable约束
    public class SNode<T> where T : IComparable<T>
    {
        public T Data { get; set; }
        public SNode<T> Next { get; set; }
        //第一个构造函数,只知道自身数据时
        public SNode(T data)
        {
            Data = data;
            Next = null;
        }
        //第二个构造函数,知道后继结点以及自身数据时
        public SNode(T data, SNode<T> next)
        {
            Data = data;
            Next = next;
        }
    }
}
  • 单链表定义(用顺序表时需要一个数组_dataset,而单链表只需要一个指针存储首结点即可):
namespace Experiment_1
{
	//实现ILinearList接口,操作与顺序表相同
    public class SLinkList<T> : ILinearList<T> where T : IComparable<T>
    {
        public SNode<T> _pHead;
        public int _length;

        public T this[int index]
        {
            get
            {
                if (index < 0 || index > _length - 1)
                    throw new ArgumentOutOfRangeException();
                return Locate(index).Data;
            }
            set
            {
                if (index < 0 || index > _length - 1)
                    throw new ArgumentOutOfRangeException();
                Locate(index).Data = value;
            }
        }

        public int Length
        {
            get
            {
                return _length;
            }
        }

		//与顺序表不同,不需要开辟大块空间,故只需初始化
        public SLinkList()
        {
            _pHead = null;
            _length = 0;
        }

		//头插法:头指针指向插入的数据
        public void InsertAtFirst(T data)
        {
            SNode<T> newNode = new SNode<T>(data);
            //若原本链表为空,则插入以后后继结点为空
            if (_length == 0)
            {
                _pHead = new SNode<T>(data, null);
            }
            else
            {
                _pHead = new SNode<T>(data, _pHead);
            }

            _length++;
        }

		//作用是配合尾插法,给一个index即返回该点指向后继结点的指针
        public SNode<T> Locate(int index)
        {
            if (index < 0 || index > _length - 1)
                throw new ArgumentOutOfRangeException();

            SNode<T> temp = _pHead;
            int i = 0;
            for (; i < index; i++)
            {
                temp = temp.Next;
            }
            return temp;
        }

		//尾插法
        public void InsertAtRear(T data)
        {
            if (_length == 0)
            {
                _pHead = new SNode<T>(data);
            }
            else
            {
                Locate(_length - 1).Next = new SNode<T>(data);
            }
            _length++;
        }

        public void Insert(int index, T data)
        {
            if (index < 0 || index > _length)
                throw new ArgumentOutOfRangeException();
            if (index == 0)
                InsertAtFirst(data);
            else if (index == _length)
                InsertAtRear(data);
            else
            {
                SNode<T> temp = Locate(index - 1);
                temp.Next = new SNode<T>(data, temp.Next);

                _length++;
            }
        }

        public void Clear()
        {
            _pHead = null;
            _length = 0;
        }

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

        public void Remove(int index)
        {
            if (index < 0 || index > _length - 1)
                throw new ArgumentOutOfRangeException();
            if (index == 0)
            {
                _pHead = _pHead.Next;
            }
            else
            {
                SNode<T> temp = Locate(index - 1);
                temp.Next = temp.Next.Next;
            }
            _length--;

        }

        public int Search(T data)
        {
            SNode<T> temp = _pHead;
            int i = 0;
            for (; i < _length; i++)
            {
                if (temp.Data.CompareTo(data) == 0)
                    break;
                temp = temp.Next;
            }
            return i == _length ? -1 : i;
        }
    }
}

(单链表和顺序表的定义均为了实现上述接口,只是结构不同)

  • 用单链表实现“查找坐标”以及“查找城市”功能:
namespace Experiment_1
{
    public class CityList : SLinkList<City>
    {
        public City[] dataInfo = new City[10];
        public double[] distances = new double[10];
        private int CDLen = 0;
        
        //查找坐标
        public City SearchPosInfo(string name)
        {
            SNode<City> temp = this._pHead;
            for (int i = 0; i < _length; i++)
            {
                if (temp.Data._name == name)
                {
                    return Locate(i).Data;
                }
                temp = temp.Next;
            }
            return null;
        }

		查找城市
        public void SearchCity(int distance, int pointX, int pointY)
        {
            SNode<City> temp = _pHead;
            for (int i = 0; i < _length; i++)
            {
                double dis = Math.Sqrt(Math.Pow((temp.Data.X - pointX), 2) + Math.Pow((temp.Data.Y - pointY), 2));
                if (dis <= distance)
                {
                    dataInfo[this.CDLen++] = temp.Data;
                    distances[this.CDLen - 1] = dis;
                }
                temp = temp.Next;
            }
        }
    }
}
  • 有关城市信息的类的定义:
namespace Experiment_1
{
    public class City : IComparable<City>
    { 
        public string _name;
        public double _x;
        public double _y;
        public City(string name, double x, double y)
        {
                _name = name;
                _x = x;
                _y = y;
        }

        public City(string name)
        {
            _name = name;
            _x = 0;
            _y = 0;
        }

        public City(int x, long y)
        {
            _name = default(string);
            _x = x;
            _y = y;
        }

        public double X
        {
            get
            {
                return _x;
            }
        }

        public double Y
        {
            get
            {
                return _y;
            }
        }

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public int CompareTo(City other)
        {
            return other._name == _name? 0 : -1;
        }

        public override string ToString()
        {
            return string.Format("Name:{0},({1},{2})", _name, _x, _y);
        }
    }
}

  • 最后在窗体应用中实现“线性表实验”:
namespace Experiment_1
{
    public partial class Form1 : Form
    {
    	//定义一个单链表用来存储城市信息
        public CityList list = new CityList();

        public Form1()
        {
            InitializeComponent();
        }

        
		//定义构造函数用来获取信息
        private City makeData()
        {
            string name = textBox1.Text;
            Double x = Convert.ToDouble(textBox2.Text);
            Double y = Convert.ToDouble(textBox3.Text);
            City city = new City(name,x,y);
            return city;
        }

		//实现“头插”
        private void button1_Click(object sender, EventArgs e)
        {
            City data = makeData();
            list.InsertAtFirst(makeData());
            Update();
        }

		//实现文本框的更新以及在文本框中将数组进行输出
        private new void Update()
        {
            richTextBox1.Clear();
            for (int i = 0; i < list.Length; i++)
            {
                City childData = list[i];
                richTextBox1.AppendText(list[i]._name + "\tX=" + list[i].X + "\tY=" + list[i].Y + "\n");
            }
        }

		//实现“尾插”
        private void button2_Click(object sender, EventArgs e)
        {
            City data = makeData();
            list.InsertAtRear(data);
            Update();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

		//实现“插入”
        private void button3_Click(object sender, EventArgs e)
        {
           City data = makeData();
           int index = Convert.ToInt32(numericUpDown1.Value);
           list.Insert(index, data);
           Update();
        }

		//实现“删除”
        private void button4_Click(object sender, EventArgs e)
        {
           int index = Convert.ToInt32(numericUpDown2.Value);
           list.Remove(index);
           Update();

        }

		//实现“更新”
        private void button5_Click(object sender, EventArgs e)
        {
           City data = this.makeData();
           int index = Convert.ToInt32(numericUpDown1.Value);
           list[index] = data;
           Update();
        }

		//实现“查找坐标”
        private void button6_Click(object sender, EventArgs e)
        {
           string name = textBox4.Text;
           City data = this.list.SearchPosInfo(name);
           if (data == null)
           {
               MessageBox.Show("并没有该城市");
           }
           else
           { 
               textBox5.Text = data.X.ToString();
               textBox6.Text = data.Y.ToString();
           }
        }

		//实现“查找城市”
        private void button7_Click(object sender, EventArgs e)
        {
            richTextBox2.Clear();
            int pointX = Convert.ToInt32(textBox7.Text);
            int pointY = Convert.ToInt32(textBox8.Text);
            int distance = Convert.ToInt32(textBox9.Text);
            list.SearchCity(distance, pointX, pointY);
            int len = this.list.dataInfo.Length;
            string str = "";
            for (int i = 0; i < len; i++)
            {
                if (list.dataInfo[i] != null)
                {
                        str += list.distances[i].ToString("Distance=0.00") + "\tCity=" + list.dataInfo[i]._name + "\tX=" + list.dataInfo[i].X + "\tY=" + list.dataInfo[i].Y + "\n";
                }
                richTextBox2.Text = str;

            }
        }
    }
    
    
}
  • 效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上官峰晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值