C# · 12月 20, 2021

顺序表(线性表)操作的思想及实现之C#版

作为线性表的两种物理结构之一,顺序存储指的是用一段地址连续的存储单元依次存储线性表的数据元素,于是,基本思想便是由数组来承担盛放这些元素的重任。对于线性表的操作,比较常见的则是获取线性表的长度GetLength(),向线性表指定位置插入一个元素Insert(),向线性表追加一个元素Add(),判断线性表是否为空IsEmpty(),获取指定位置的元素GetElement(),删除指定位置的元素Delete(),在线性表中查找与给定值相等的元素并提示该元素所在的位置或者查找失败LocateElement()及反转线性表Reverse(),如下代码定义的方法便是我们需要花时间思考如何实现的:

由于使用的是数组,因此我们需要先定义一些前提条件以便日后使用:

其中始终指向最后一个元素位置的intPointLast初始化时将其值设为-1,这意味着数组中元素为0,一切从头开始。到现在,我们已经明白了需要实现的目标,接下来就是要一步一步到达这个目标。

获取线性表长度GetLength()

第一反应是要得到数组长度,那直接返回tItem的长度是不是就是我们所要的结果了呢?错!没有任何明文规定线性表的长度就是数组的长度,,因此,获取数组的长度结果并非线性表的实际长度。那么,如何获得线性表的长度呢?啊哈,刚刚我们定义过intPointLast,它始终是指向最后一个元素的位置不是么?也就是说,它的值是多少,不就是线性表有多少元素了么?错!既然是用数组实现,那就得按数组的规矩来,数组的下标是从0开始的,这也就是为什么intPointLast的初始值为-1能表示数组中元素为0的原因,同样的道理,我们要获取线性表的长度,必然需要。

向线性表中指定位置插入一个元素Insert()

要实现这个方法,首先我们需要考虑它的条件,在指定位置,也就是我们需要知道在数组中的一个位置,插入元素,意味着要知道这个新的元素是什么,于是,这个方法理所当然就有两个参数,于是方法应该是这样的:Insert(T item,int i),定义成T是使用泛型来完成这个方法,可以避免装箱拆箱的繁琐工作。

好了,到这里,很容易的,我们可以知道如何插入元素:1,从最后一个元素开始向前遍历到第i个位置,然后将它们向后移动一个位置,2,将要插入的元素填入到空出来的位置中,3,表长+1。

看起来实现很简单嘛,可是,数组从0开始,假设数组容量是100,在Insert的方法中我将元素插入到101的位置怎么办?又或者,刚刚提到,线性表的长度应该小于或者等于数组的长度,假设初始的线性表已经等于数组长度了,那么再在任何地方插入一个元素都会导致数组溢出,这又怎么办?没错,在进行线性表插入的操作中,我们需要先对这些条件做个判断,于是代码应该是这样的:

  public void Insert(T item,int i) { if (i<1 || i>this.intPointLast+1) { Console.WriteLine(“The inserting location is wrong”); return; } if (this.IsFull()) { Console.WriteLine(“The linear list is full,can’t insert any new items”); return; } this.intPointLast++; for (int j = this.intPointLast; j >= i; j–) { this.tItems[j] = this.tItems[j – 1]; } this.tItems[i] = item; }

向线性表追加一个元素Add()

相比向线性表指定位置添加元素来说,这个方法不过是指定了在线性表最末做Insert操作,由于在最末尾添加元素,所以原有的元素不需要任何变动,只需判断原来的线性表的长度是否已等于数组的长度,如果是,那么意味着无法插入,如果不是,那么只需对线性表加1,并把新增的线性表元素添加到其中即可:

判断线性表是否为空IsEmpty()

这个前面已经说过了,只需要判断intPointLast的值是否为-1即可:

获取指定位置的元素GetElement()

要获取指定位置的元素,也就是需要指定的位置,于是,该方法需要一个参数来告知元素从哪里获取:GetElement(int i),要实现这个也很简单,只需要得到数组下标就可以了,于是,理所当然的只要一句话:return tItems[i],好,可以进行下一个话题讨论了。等等,跟在指定位置插入元素的时候一样,如果数组容量只有100,而我要获得第101的位置的值怎么办?如果数组里什么都没有的话,又要让程序返回什么呢?这个时候恍然大悟:

this.intPointLast || i<0) { Console.WriteLine("Exceed the capability"); return default(T); } return tItems[i];}

删除指定位置的元素Delete()

同样的,我们需要一个参数来告知删除的位置:Delete(int i),有了前车之辙,现在我们明白考虑问题需要周全点了,好吧,先来看看,有什么值得注意的地方,其一,线性表为空时无法删除,其二,删除的位置不对时,无法删除,如果满足了可被删除的条件,那么,接下来要考虑的是取出要删除的元素,并从这个位置开始遍历到最后一个元素的位置,将它们向前移动一个位置,线性表的表长减1,有了实现思路,代码就容易多了:

this.intPointLast || i < 0) { Console.WriteLine("Deleting locate is wrong"); return; } for (int j = i; j < this.intPointLast; j++) { this.tItems[j] = this.tItems[j + 1]; } this.intPointLast–;}

查找与给定值相等的元素LocateElement()

要查找是否存在一个值与给定值相等,那么必须保证线性表不为空,否则该操作没有任何意义,而是否存在这么一个值与给定值相等,只需要遍历线性表,并且将每一个值与给定值进行比较即可:

反转线性表Reverse()

继续吸取之前的经验教训,要对一个线性表进行操作,线性表必须不为空,因此第一步就是判断线性表是否为空,当线性表不为空的时候,我们该如何使用循环对其进行反转呢?先设定一个游标从起始位置,但是循环的终结点在哪里?经过分析我们可以知道,只需要将循环终结点设定在线性表长度一半的位置,然后将i位置的元素值与intPointLast-i位置元素的值进行颠倒即可,于是便有了以下代码:

好吧,顺序表的部分常用操作就介绍到这里~生活开心,学习愉快~