题外话:这两天感觉转性了,只想学习不想玩了,难道要成为大神了?哈哈哈哈
PS: 本文的重点是代码代码代码!而不是数据结构的一些基础概念和分类;
完全没接触过的同学,可以去看B站王卓教授的视频。
1.什么是顺序表?
-
把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。
-
即线性表的顺序存储结构,必须占用一片连续的存储空间。
-
这货和链表什么关系?
- 恭喜你! 盲僧,你发现了华点!!
- 顺序表和链表本质上都是线性表,但是!!!
- 顺序表他不是内存空间连续嘛;
- 链表的内存空间不一定连续,东一块西一块也行,这就是他俩的差别。
2.什么时候使用顺序表?
- 数据访问量比较大,且新增、删除操作不频繁的数据。
3.顺序表和数组的关系
- 可以理解为数组是顺序表的一种实现,数组就是顺序表;
- 因为高级语言都帮你实现了数组的底层设计,所以开发者当他是顺序表直接拿来用即可。
4.总结:什么是顺序表?
- 逻辑上相邻,存储结构也相邻的数据结构,叫顺序表。
5.代码实现
namespace YoyoCode
{
//顺序表
internal class SqList<T> where T : class
{
/// <summary>
/// 数组默认最大容量
/// </summary>
public int MaxSize = 8;
/// <summary>
/// 存放元素的数组
/// </summary>
private T[] _array;
/// <summary>
/// 数组中元素的数量
/// </summary>
public int Count = 0;
public SqList()
{
_array = new T[MaxSize];
}
public SqList(int maxSize)
{
MaxSize = maxSize;
_array = new T[MaxSize];
}
/// <summary>
/// 在顺序表尾端添加元素
/// </summary>
/// <param name="value">添加的值,类型为T</param>
/// <returns>bool,是否添加成功</returns>
public bool Add(T value)
{
if (Count == MaxSize)
{
Console.WriteLine("数组已满,无法添加元素!");
return false;
}
_array[Count++] = value;
return true;
}
/// <summary>
/// 获取对应索引的元素
/// </summary>
/// <param name="idx">索引值</param>
/// <returns>T</returns>
public T? Get(int idx)
{
if (idx >= Count || idx < 0)
{
return null;
}
return _array[idx];
}
/// <summary>
/// 获取顺序表最后一个元素
/// </summary>
/// <returns>T</returns>
public T? GetLast() {
if (IsEmpty())
{
return null;
}
return _array[Count- 1];
}
/// <summary>
/// 顺序表是否为空
/// </summary>
/// <returns>bool,表是否为空</returns>
public bool IsEmpty()
{
return Count == 0;
}
/// <summary>
/// 清空顺序表(逻辑清空)
/// </summary>
public void Clear()
{
//逻辑清空(遍历_array时不用foreach,而是用Count)
Count= 0;
}
/// <summary>
/// 在对应的索引插入元素,
/// 不支持不连续的插入,例如数组总共3个元素,索引从0-2,你要在索引4插入,非法
/// </summary>
/// <param name="value"></param>
/// <param name="idx"></param>
/// <returns>bool,是否插入成功</returns>
public bool Insert(T value, int idx) {
if(Count == MaxSize)
{
Console.WriteLine("数组已满,无法添加元素!");
return false;
}
if (idx < 0 || idx > Count)
{
Console.WriteLine("插入位置有误!");
return false;
}
//从后向前插入,省一个空间
for (int i = Count; i > idx; i--)
{
_array[i] = _array[i - 1];
}
_array[idx] = value;
Count++;
return true;
}
/// <summary>
/// 删除某个索引的元素
/// </summary>
/// <param name="idx">被删除元素的索引</param>
/// <returns>bool,是否删除成功</returns>
public bool RemoveAt(int idx)
{
if (idx < 0 || idx >= Count)
{
Console.WriteLine("插入位置有误!");
return false;
}
//从前向后遍历,省一个空间
for (int i = idx; i < Count; i++)
{
_array[i] = _array[i + 1];
}
Count--;
return true;
}
/// <summary>
/// 遍历顺序表中所有的元素,并执行你希望的操作。
/// 例如:你可以通过该函数实现Contains的功能,判断表中是否存在某个元素。
/// </summary>
/// <param name="func">返回值为bool,参数为T的委托,bool为true时会打断循环</param>
public void Traverse(Func<T, bool> func)
{
for (int i = 0; i < Count; i++)
{
if (func(_array[i])) {
break;
}
}
}
}
}
说明:
- 该类使用了泛型,且必须是类类型才可以。.
- 该类提供了遍历函数Traverse,可通过传入委托实现各种你需要的遍历操作。
6.都有数组了,为什么要自己实现?
- 首先,我在学数据结构,只有手敲一遍才能理解该结构的优缺点。
- 其次,C#提供的数组其实也不是很方便,缺少很多对数组的操作,比如插入删除遍历等,所以自己实现了,以后自己代码也能用哦。
- 最后,,,啊。。。嗯。。。好像没了hhh。
7.顺序表的优缺点
- 优点:
- 存储密度大,即存储结构中(_array),100%的空间都给到元素使用了。
- 可随机存取表中任意元素,时间复杂度为O(1)。
- 缺点:
- 插入、删除、查找的时间复杂度为O(n);
- 浪费存储空间,且静态存储(数组大小固定了,无法扩容)
结束语: 这一鸽就是好几个月哈哈哈,后面会增加几篇数据结构相关的文章。大学的《数据结构与算法》教材教啥我就写啥。
你一定要支棱起来啊!!!让看不起你的人对你刮目相看!!!