C#数据结构学习:线性结构之顺序表
什么是线性表
上篇我们提及到了单向链表的具体功能和实现,这次我们来学习一下线性表之顺序表的功能与实现。
通过前面问题的启示:
①同一个问题可以有不同的存储方法。
②这一类问题都是有序线性序列的组织和管理。
我们就把这类有序线性序列称作为线性表,数据结构最常见的存储方式要么是数组存储,要么是链表存储
总结一下
线性表:由同类型数据元素构成有序序列的线性结构
①表中元素个数为线性表的长度
②线性表没有元素时,称为空表
③表起始位置叫表头,表结束位置叫表尾
线性表的抽象数据类型描述
类型名称:线性表(List)
数据对象集:线性表是n(≥0)个元素构成的有序序列(a1,a2…an)
操作集:线性表L∈List,整数i表示位置,元素X∈ElementType(整型,结构,实型等)
其中操作集有以下操作:
①List MakeEmpty():初始化一个空线性表L;
②ElementType FindKth(int k,List L):根据位序k,返回相应元素
③int Find(ElementType X,List L):在线性表中查找X元素第一次出现的位置
④void Insert(ElementType X,int i,List L):在位序i前插入新元素X
⑤void Delete(int i,List L):删除指定位序i的元素
⑥int Length(List L):返回表的长度n
下面是顺序表的具体实现和定义:
class SeqList<T>
{
private T[] Name;//顺序表表名
private int Size;//顺序表当前最大的容量
private int last;//最后的索引值
public SeqList(int size)//初始化函数
{
this.Size = size;
Name = new T[size];
}
public int Find(T Value)//找寻第一次出现的位置
{
for (int i = 0; i < Size; i++)
{
if (Name[i].Equals(Value))
{
return i;
}
}
return -1;
}
public T GetVaule(int Index)
{
if (Index > Size || Index < 0)
{
throw new Exception("索引超出范围");
}
T value = Name[Index];
return value;
}
public void Insert(T Value, int Index)//在index前面插入数据
{
if (Index>Size||Index<0)
{
throw new Exception("索引超出范围");
}
for (int i = Size-1; i >= Index; i--)//往后移一位
{
Name[i] = Name[i - 1];
}
Name[Index] = Value;
last++;
}
public void Add(T Value)
{
Name[last] = Value;
last++;
}
public void Delete(T Value, int Index)
{
if (Index > Size || Index < 0)
{
throw new Exception("索引超出范围");
}
if (!Name[Index].Equals(Value))
{
throw new Exception(string.Format("索引{0}不存在{1}值",Value,Index));
}
for (int i = Index; i <Size-1; i++)//直接进行覆盖值操作
{
Name[i] = Name[i+1];
if (i+1 == Size-1)
{
Name[i + 1] = default(T);//最后一项清零
}
}
last--;
}
}
下面让我们验证一下:
//顺序表
SeqList<string> a = new SeqList<string>(5);
Console.WriteLine("-------------------进行赋值操作-----------------------");
for (int i = 0; i < 5; i++)
{
a.Add(i.ToString());
}
Console.WriteLine("-------------------重新输出一遍-----------------------");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("索引值{0}处的值为{1}",i,a.GetVaule(i));
}
Console.WriteLine("-------------------进行删值操作-----------------------");
a.Delete("2", 2);
Console.WriteLine("-------------------重新输出一遍-----------------------");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("索引值{0}处的值为{1}", i, a.GetVaule(i));
}
Console.WriteLine("-------------------进行插值操作-----------------------");
a.Insert("100", 3);
Console.WriteLine("-------------------重新输出一遍-----------------------");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("索引值{0}处的值为{1}", i, a.GetVaule(i));
}
Console.WriteLine("-------------------进行寻值100操作--------------------");
Console.WriteLine("该值的第一次出现的索引是{0}",a.Find("100"));
Console.ReadKey();
运行结果:
逻辑符合
注意:
本文只实现顺序表的删增改查功能,具体求表长,清空等功能请看这篇文章
https://www.jianshu.com/p/f6c415785ac9
总结:
在删值的时候没必要用default(T),直接往前移一位把前面的值覆盖就行了,但是要记得把最后一项清零,否则末尾数据会重复。
在移项的时候,往空出来的方向移,比如在删值操作,对于要移的项来说,前面有空位,所以是往前移;在插值操作,对于要移的项来说,后面有空位,所以是往后移,这点需要注意,不然会出现目标项后面的项值都是末尾数据。
跟链表相比,链表只需要修改链(下一个数据存储地址)和数据值即可,在进行删除插入的操作时候,不需要往前移或者往后移数据元素。