代码
节点类
class Node
{
public string Name;
public int X, Y;
public Node Next;
public Node(string name, int x, int y, Node next)
{
Name = name;
X = x;
Y = y;
Next = next;
}
public override string ToString()
{
return string.Format("{0} 坐标:({1},{2})", Name, X, Y);
}
}
这里把城市的属性和节点封装在了一起 并没有使用泛型 因为本题只针对城市一种类型 没有必要
其次是链表类的定义中用到了三种有不同参数的搜索函数 需要访问城市的属性
如果把城市的属性另外封装在一个类中 使用泛型将不好访问类的成员(也许有其他方法规避这个问题)//已解决 可以重载接口中的CompareTo方法
覆写了节点类的Tostring方法 以便接下来在listbox中添加显示
链表主体定义
class Linklist
{
int length;
Node pHead;
public int Length
{
get { return length; }
}
public Node this[int index]
{
get
{
return ElementAt(index);
}
set
{
ElementAt(index).Name = value.Name;
ElementAt(index).X = value.X;
ElementAt(index).Y = value.Y;
}
}
public Linklist()
{
length = 0;
pHead = null;
}
public void Indexcheck(int index)
{
if (index < 0 || index > length - 1)
throw new IndexOutOfRangeException();
}
#region 查找函数重载
public int IndexOf(string name)
{
int i;
Node temp = pHead;
for (i = 0; i < length; i++)
{
if (temp.Name.Equals(name))
break;
temp = temp.Next;
}
return i == length ? -1 : i;
}
public int IndexOf(int x, int y)
{
int i;
Node temp = pHead;
for (i = 0; i < length; i++)
{
if (temp.X == x && temp.Y == y)
break;
temp = temp.Next;
}
return i == length ? -1 : i;
}
public int IndexOf(string name,int x, int y)
{
int i;
Node temp = pHead;
for (i = 0; i < length; i++)
{
if (temp.X == x && temp.Y == y && temp.Name.Equals(name))
break;
temp = temp.Next;
}
return i == length ? -1 : i;
}
#endregion
public Node ElementAt(int index)
{
Indexcheck(index);
Node temp = pHead;
for (int i = 0; i < index; i++)
{
temp = temp.Next;
}
return temp;
}
public void Insert(Node city, int index) //这里传进来的city.Next=null
{
if (length == 0)
{ pHead = city; }
else
{
//Indexcheck(index);
if (index < 0 || index > length) throw new ArgumentOutOfRangeException();
if (IndexOf(city.Name) != -1) { throw new Exception("已有同名城市"); }
if (index == 0)
{
Node temp = pHead;
pHead = city;
city.Next = temp;
}
else if (index == length) { ElementAt(length - 1).Next = city; city.Next = null; } //length++ }
else
{
city.Next = ElementAt(index);
ElementAt(index - 1).Next = city;
}
}
length++;
}
public void Clear()
{
pHead = null;
length = 0;
}
public bool IsEmpty() { return length == 0; }
public void Remove(int index)
{
if (length == 0) return;
else if (index == 0) pHead = pHead.Next;
else if (index == length - 1) ElementAt(index - 1).Next = null;
else ElementAt(index - 1).Next = ElementAt(index + 1);
length--;
}
}
以上包含了城市链表的各种方法及属性的定义
其中IndexOf方法是搜索方法,用了三种不同的重载类型,分别是查名字、查坐标、查名字+坐标(默认城市名字与坐标都不一样 下有查重但是只查了名字)
Insert方法包括首插和尾插 只需要填写相应的index即可
如果要做窗体程序的话 链表中的各项输入参数的检查应该是不必要的 因为可以在窗体中实现输入参数的检查(可能个别地方仍然需要)
窗体
public partial class Form1 : Form
{
Linklist citylist = new Linklist();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void listBox_refresh()
{
CitylistBox.Items.Clear();
for (int i = 0; i < citylist.Length; i++)
{
CitylistBox.Items.Add(citylist[i]);
}
}
private void InsertBtn_Click(object sender, EventArgs e)
{
try { int.Parse(CityXTB.Text); int.Parse(CityYTB.Text); int.Parse(InsertIndexTB.Text); }
catch { MessageBox.Show("输入参数不正确"); return; }
int index = int.Parse(InsertIndexTB.Text) - 1;
if (index < 0 || index > citylist.Length) { MessageBox.Show("插入位置超出索引范围"); return; }
if (citylist.IndexOf(CitynameTB.Text) != -1) { MessageBox.Show("已有同名城市"); return; }
Node newcity = new Node(CitynameTB.Text, int.Parse(CityXTB.Text), int.Parse(CityYTB.Text), null);
citylist.Insert(newcity, int.Parse(InsertIndexTB.Text) - 1);
listBox_refresh();
}
private void UpdateBtn_Click(object sender, EventArgs e)
{
if (CitylistBox.SelectedIndex == -1)
{
MessageBox.Show("未选定城市");
return;
}
try { int.Parse(UpdateCityXTB.Text); int.Parse(UpdateCityYTB.Text); }
catch { MessageBox.Show("输入参数不正确"); return; }
//citylist[CitylistBox.SelectedIndex].Name = UpdateCitynameTB.Text;
//citylist[CitylistBox.SelectedIndex].X = int.Parse(UpdateCityXTB.Text);
//citylist[CitylistBox.SelectedIndex].Y = int.Parse(UpdateCityYTB.Text);
citylist[CitylistBox.SelectedIndex] = new Node(UpdateCitynameTB.Text, int.Parse(UpdateCityXTB.Text),
int.Parse(UpdateCityYTB.Text), citylist[CitylistBox.SelectedIndex].Next);
listBox_refresh();
}
private void SearchBtn_Click(object sender, EventArgs e)
{
if (citylist.IndexOf(SearchCitynameTB.Text) != -1)
{
Node currentcity = citylist[citylist.IndexOf(SearchCitynameTB.Text)];
SearchLocation.Text = string.Format("({0},{1})", currentcity.X, currentcity.Y);
}
else { MessageBox.Show("未找到所给城市"); SearchLocation.Text = "(,)"; return; }
}
private void MatchBtn_Click(object sender, EventArgs e)
{
try { double.Parse(MatchDistanceTB.Text); int.Parse(MatchXTB.Text); int.Parse(MatchYTB.Text); }
catch { MessageBox.Show("输入参数不正确"); return; }
MatchResult.Text = null;
List<Node> Resultlist = new List<Node>();
double distance = 0;
int x = int.Parse(MatchXTB.Text), y = int.Parse(MatchXTB.Text);
for (int i = 0; i < citylist.Length; i++)
{
distance = Math.Sqrt((citylist[i].X - x) * (citylist[i].X - x) + (citylist[i].Y - y) * (citylist[i].Y - y));
if (distance < double.Parse(MatchDistanceTB.Text))
Resultlist.Add(citylist[i]);
}
if (Resultlist.Count != 0)
{
foreach (Node city in Resultlist)
{
MatchResult.Text += (city.Name + '\n');
}
}
else
MatchResult.Text = "无";
}
private void DeleteBtn_Click(object sender, EventArgs e)
{
if (CitylistBox.SelectedIndex != -1)
{
citylist.Remove(CitylistBox.SelectedIndex);
listBox_refresh();
}
else
{
MessageBox.Show("未选定城市");
return;
}
}
}
窗体部分代码 包括各项输入参数的检查
listbox_refresh方法用于城市链表修改以后更新listbox中的显示
使用此方法资源浪费很大 会执行许多不必要的语句 但是省事
更正确节约的方法应该是每处对链表进行修改后对listbox也做出相应的修改 不需要整体全部刷新
运行效果: