(精华)2020年8月27日 数据结构与算法解析(数组)

引言:数据结构的基本概念

我们先来回顾下数据结构的几个概念。

何谓数据结构?专门研究数据之间的逻辑关系、存储方式及操作的学问就是所谓的数据结构。

数据的逻辑结构
数据元素之间存在的关联关系(与它们在计算机中的存储位置无关),被称为数据的逻辑结构。

从数据的逻辑结构划分大致有如下4中逻辑结构:

  1. 集合:数据元素之间只有"同属于一个集合"的关系
  2. 线性结构:数据元素之间存在"一对一"的关系
  3. 树形结构:数据元素之间存在"一对多"的关系
  4. 图状结构或网状结构:

数据的存储结构
对于数据不同的逻辑结构,在底层通常通常有两种物理存储结构(数据元素在计算机存储空间的存放形式):

  1. 顺序存储结构(线性表)
  2. 链式存储结构(链表)

对上面的内容用思维导图小结下:
在这里插入图片描述
线性表
对于常用的数据结构可以分为线性结构和非线性结构。线性结构主要是线性表,非线性结构主要是树和图。

从上面对数据结构的逻辑结构介绍中得知, 数据元素之间存在"一对一"的关系, 即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意循环l链表也是线性结构,但是它首尾是相接的)。

线性表的每个元素必须有相同的结构(元素可以是简单的数据,也可以是复杂的数据,但复杂的数据内部结构要相同)。

线性表的基本操作

  1. 线性表初始化
  2. 插入元素
  3. 向指定位置插入元素
  4. 删除元素
  5. 删除指定位置的元素
  6. 取指定位置的元素
  7. 查找元素的位置
  8. 返回线性表的长度
  9. 判断线性表是否为空
  10. 清空线性表

线性表主要有两种存储结构:顺序存储(线性表)、链式存储(链表)。本篇文章主要介绍顺序存储,链式存储放在下一个篇文章。

顺序结构存储是指用一组地址连续的存储单元一次存放线性表中的元素。也就是说,顺序结构线性表中的数据元素的物理关系和逻辑关系是一致的。所以如果线性表采用顺序存储,往线性表中间的某个位置插入或者删除元素需要对该位置及其之后的元素进行移动。

顺序存储结构的线性表中间位置插入新元素

首先要把该位置及其之后的元素往后移一位,为新元素腾出空间。

往索引 index=2 的位置插入元素:
在这里插入图片描述
把索引index=2及其后面的所有元素往后移一格,为新元素腾出位置:
在这里插入图片描述
插入新元素
在这里插入图片描述
删除顺序存储结构的线性表中间位置元素
删除顺序存储结构的线性表中间位置的元素,操作类似。

删除索引index=2的元素:在这里插入图片描述
删除元素:
在这里插入图片描述
把index=2之后的所有元素向左移动一格:
在这里插入图片描述
顺序存储的线性表,采用数组存储,插入元素如果容量不够,需要进行扩容。扩容主要是创建一个新的数组,然后把数据从老数组拷贝到新的数组中。

一:数组

数组主要有Array,ArrayList,List

Array

数组在C#中最早出现的。在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单。

<span style="font-family:SimSun;font-size:18px;">//数组  
string[] s=new string[2];  
  
//赋值  
s[0]="a";  
s[1]="b";  
//修改  
s[1]="a1";  
</span>

优点:数组在内存中是连续存储的、所以它的索引速度是非常快的、时间复杂度为O(1)、而且它的赋值/修改/获取元素也是非常简单的。

缺点:1、定义数组的时候需要指定数组的长度(过长会造成内存浪费、过短会导致程序异常System.IndexOutOfRangeException:“索引超出数组界限”)

2、插入和删除元素效率低、也比较麻烦。

在不清楚数组长度的时候、就很尴尬了。 所以C#提供了ArrayList了来处理这些问题…

ArrayList

使用大小会根据需要动态增加的数组。

//初始化
ArrayList list = new ArrayList();

//添加元素
list.Add(1);
list.Add("A");
list.Add(0.1);

//修改元素
list[2] = "B";

//指定索引插入元素
list.Insert(1, "ABC");
            
//移除元素
list.RemoveAt(1);

优点:1、ArrayList大小会根据需要动态增加的数组。

2、实现了IList接口、可以方便的对数据进行添加、插入和删除。

缺点:1、ArrayList会把插入的数据都当做object类型来存储、在操作数据的时候可能会因为类型不匹配而出现异常、它是非类型安全的对象。

2、由于存储的是object类型、在使用的时候进行类型转换、会造成装箱拆箱、从而损耗性能。

装箱:把值类型转换成引用类型;

拆箱:把引用类型转换成值类型。

//装箱
int i = 1;
object obj = (object)i;
//拆箱
int j = (int)obj;

由于ArrayList存在类型不安全、装箱拆箱损耗性能。.NET Framework 2.0 推出了List

List

表示可通过索引访问的对象的强类型列表。 提供用于对列表进行搜索、排序和操作的方法。

//初始化
List<int> list = new List<int>();

//添加
list.Add(12);
list.Add(34);

//编译器会进行类型验证、下面代码编译失败
//list.Add("ABC");

//修改
list[0] = 1;

//移除
list.RemoveAt(0);

优点:由于泛型List是强类型、编译器会验证类型安全。这样就避免了类型的不安全、以及数据强制转换导致装箱拆箱损耗性能。

备注:哈希表(散列),就是数组的升级版通过hash运算快速查找到值,数组下标就是哈希值。(前512是int,后才是哈希)

©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页