- 线性表接口定义,将有关线性表的操作封装到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;
}
}
}
}
- 效果如下: