【以练促学:数据结构】2.线性表
(持续刷题,持续更新...)
1.顺序表与链表的比较
(空间性能) | 顺序表 | 链表 | |
顺序存储结构 | 链式存储结构 | ||
逻辑相邻,物理存储位置相邻 | 逻辑相邻,物理存储位置未必相邻 | 顺序表必须是连续物理存储空间 | |
存储空间分配 | 必须预先分配 | 不用预先分配 | |
存储密度 | 1 | 小于1 | 顺序表的存储密度更大 |
(时间性能) | 顺序表 | 链表 | |
随机存取 | 顺序存取 | ||
存储元素效率 | O(1) | O(n) | |
插入/删除操作的效率 | O(n) | O(1) | 链表的 插入/删除操作更方便 |
查找操作的效率 | O(1) | O(n) | 顺序表的 查找操作更方便 |
eg:下列( )是顺序存储结构的优点
A. 存储密度大
B. 插入运算方便
C. 删除运算方便
D. 方便地运用于各种逻辑运算的存储表示
// 顺序表存储密度大(不用在结点中存放指针),D中,对于树形结构还是链式的更方便
eg:线性表的顺序存储结构是一种( )
A. 随机存取的存储结构
B. 顺序存取的存储结构
C. 索引存取的存储结构
D. 散列存取的存储结构
// 存取方式指读写方式,顺序表随机存取,即根据其下标可以很方便的访问任意元素
eg:对于一个线性表,既要求能够进行较快的插入和删除,又要求存储结构能够反映数据间的逻辑关系,则应该用( )
A. 顺序存储方式
B. 链式存储方式
C. 散列存储方式
D. 以上均可
// 顺序存储方式(就是一个个找),不能较快插入/删除(要移后面的数据);散列存储通过散列函数映射到物理空间,不能反映数据间逻辑关系;链式存储方式两个都能满足:既能较快的插入/删除(O(1)),又能表示各种逻辑关系
eg:若线性表最常用的操作是存取第 i 个元素及其前驱和后继元素的值,为了提高效率,应采用( )的存储方式
A. 单链表
B. 双向链表
C. 单循环链表
D. 顺序表
// ABC链表都只能从头开始依次顺序查找 O(n),顺序表可以直接根据下标随机存取 O(1)
eg:若线性表最常用的操作是存取第 i 个元素及其前驱的值,则采用( )存储方式节省时间
A. 单链表
B. 双向链表
C. 单循环链表
D. 顺序表
// 要取前驱,首先排除单链表,而在双链表和顺序表中,顺序表的随机存取又优于双链表
eg:在n个元素的线性表的数组表示中,时间复杂度为 O(1) 的操作( )(多选)
A. 访问第 i(1<= i <= n)个结点和求第 i(2<= i <= n)个结点的直接前驱
B. 在最后一个结点后插入一个新的结点
C. 删除第1个结点
D. 在第 i(1<= i <= n)个结点后插入一个结点
// 线性表随机存取,访问第 i 和 i-1 的结点为 O(1);在尾巴上新增(不用移动结点)也是 O(1);删除和插入结点后,均需要依次移动后面的结点,故为 O(n);
eg:设线性表有 n 个元素,严格来说,以下操作中,( )在顺序表上实现要比链表上实现效率高(多选)
A. 输出第 i(1<= i <= n)个元素值
B. 交换第3个元素与第4个元素的值
C. 顺序输出这 n 个元素的值
// A顺序表 O(1),链表 O(n);B顺序表中交换元素要找个中间商,进行3次交换;而链表要分别找到3/4结点的前驱,第4个结点断链后接到2后面(比较复杂);C顺序输出时顺序表和链表均 O(n)
eg:对于顺序表,访问第 i 个位置的元素,和在第 i 个位置插入一个元素的时间复杂度分别为( )
A. O(n),O(n)
B. O(n),O(1)
C. O(1),O(n)
D. O(1),O(1)
// 顺序表的访问是随机存储 O(1),插入元素需要后面的元素给它腾位置,所以是 O(n)
eg:单链表的存储密度( )
A. 大于1
B. 等于1
C. 小于1
D. 不确定
// 存储密度指:数据元素本身所占存储量:整个结点结构所占存储量;链表结点要额外放置指针域,所以存储密度一定小于1
eg:对于单链表表示法,以下说法错误的是( )
A. 数据域用于存储线性表的一个数据元素
B. 指针域或链域用于存放一个指向本结点的直接后继结点的指针
C. 所有数据通过指针的链接而组织成单链表
D. NULL称为空指针,它不指向任何结点,只起标志作用
// “所有数据通过指针的链接而组织成单链表”,应该是所有结点(包括数据、指针)通过指针的链接而组织成单链表
2.线性表元素序号从1始,下标索引从0始
eg:若长度为 n 的非空线性表采用顺序存储结构,在表的第 i 个位置插入一个数据元素,则 i 的合法值应该是( )
A. 1<= i <= n
B. 1<= i <= n+1
C. 0<= i <= n-1
D. 0<= i <= n
// 线性表元素的序号是从1开始的,而在第 n+1 的位置相当于在表尾追加
3. 静态链表
- 静态链表要预先分配一块连续的内存空间
- 静态链表借助数组来描述线性表的链式存储结构(非随机存取)
- 静态链表的指针是结点的相对地址(数组下标),又称游标
- 静态链表的插入/删除操作与动态链表相似:只需修改指针,不用移动元素
eg:以下关于线性表说法正确的是( )(多选)
A. 顺序存储方式只能用于存储线性结构
B. 取线性表的第 i 个元素的时间与 i 的大小有关
C. 静态链表需分配较大的连续空间,插入和删除操作不需要移动元素
D. 在一个长度为 n 的有序单链表中插入一个新结点并仍保持有序的时间复杂度是O(n)
E. 若用单链表来表示队列,则应选用带尾指针的循环链表
// 顺序存储方式除了适用于存储线性结构,还有图和树;线性表包括顺序表和链表,顺序存储时是随机存取的和 i 无关;静态链表需分配较大的连续空间,插入和删除操作不需要移动元素;队列(头删尾进)采用带尾指针的循环链表较方便,插入/删除的时间复杂度为 O(1)
eg:静态链表中的指针表示( )
A. 下一元素的地址
B. 内存储器地址
C. 下一个元素在数组中的位置
D. 左键/右键指向的元素地址
// 静态链表中的指针又称游标,指示下一个元素在数组中的下标
eg:需要分配较大空间,插入和删除不需要移动元素的线性表,其存储结构为( )
A. 单链表
B. 静态链表
C. 顺序表
D. 双链表
// 静态链表用数组表示,因此需要预先分配较大的连续空间;同时,静态链表的插入/删除操作与动态链表相似:只需修改指针,不用移动元素
4. 链表的时间复杂度
- 单链表的查找/建立 :O(n)
- 数组排序(折半查找)复杂度O(nlog2n)
eg:给定有 n 个元素的一维数组,建立一个有序单链表的最低时间复杂度为( )
A. O(1)
B. O(n)
C. O(n2)
D. O(nlog2n)
// “有序单链表”就是有顺序的单链表,有两种实现方式:①先建立,再依次插入(每次插入一个元素就需要遍历以寻找插入位置),时间复杂度为:O(n2);②先给数组排序O(nlog2n),再建立链表 O(n),总时间复杂度为:O(nlog2n);综上,O(n2) 和 O(nlog2n) 中最低的是 O(nlog2n)
eg:线性表(a1,a2,...,an)以链接方式存储时,访问第 i 个位置上元素的时间复杂度为( )
A. O(i)
B. O(n)
C. O(n2)
D. O(nlog2n)
// 可以理解为,时间复杂度是算法问题规模 n 的函数,时间复杂度主要是分析 T(n) 的数量级
5. 合并表
- (无条件合并)A+B:遍历到链表A 的尾节点,然后将 next 域指向链表B 的首结点,时间复杂度 O(A)
- (有序表合并)A+B:
- 合并后按原序:最好情况是一个表中元素全部小于另一表,时间复杂度 O(min(A,B));最坏情况是两表元素交替,时间复杂度 O(A+B)
- 合并后按原序的逆序排列:最好/坏情况的时间复杂度都是 O(A+B)
eg:将长度为 n的单链表链接在长度为m的单链表后面,其算法的时间复杂度为( )
A. O(1)
B. O(n)
C. O(m)
D. O(n+m)
// “将长度为n的单链表链接在长度为 m 的单链表后面”就是:m+n,遍历到 m 的尾节点,然后将 next 域指向另一个表的首结点,时间复杂度为 O(m)
eg:已知两个长度分别为 m 和 n 的升序链表,若将它们合并为一个长度为 m+n 的降序链表,则最坏情况下的时间复杂度为( )
A. O(n)
B. O(m*n)
C. O(min(m,n))
D. O(max(m,n))
// “将升序链表合并为降序”,最好/坏情况的时间复杂度都是 O(m+n),所以很奇怪的就是O(max(m,n))
6. 链表基础操作
- 带头结点/不带头结点:
- 有头:第一个结点不保存数据,区别于其他数据结点(更方便插入/删除操作)
- 无头:第一个结点直接就存数据了
- 插入:
- 删除:
- (单链表)从头结点开始顺序查找到其前驱,再执行删除,O(n)
- (单链表)直接覆盖 ,O(1),但要注意尾指针是特殊情况(尾指针不能指空)
- 一般用单链表删除尾结点元素很不方便(建议用双链表),删除尾结点要从头遍历到尾结点的前驱结点,并置空它
- 判空:
- (带头结点)head->next==NULL
- (不带头结点)head==NULL
eg:在一个长度为 n 的带头结点的单链表 h 上,设有尾指针 r,则执行( )操作与链表的表长有关
A. 删除单链表中的第一个元素
B. 删除单链表中的最后一个元素
C. 在单链表第一个元素前插入一个新元素
D. 在单链表最后一个元素后插入一个新元素
// “删除单链表的最后一个结点”,需要置空其前驱结点的指针域为NULL(要从头遍历),需要O(n)的时间,与表长相关
eg:若一个链表最常用的操作是在末尾插入和删除结点,则选用( )最节省时间
A. 带头结点的双循环链表
B. 单循环链表
C. 带尾指针的单循环链表
D. 单链表
// 根据删除尾结点的特殊性(单链表要从头遍历),建议选择双链表
eg:设对 n(n>1) 个元素的线性表的运算只有4种:删除第一个元素,删除最后一个元素,在第一个元素之前插入新元素,在最后一个元素之前插入新元素;则最好使用( )
A. 只有尾结点指针,没有头结点指针的循环单链表
B. 只有尾结点指针,没有头结点指针的非循环双链表
C. 只有头结点指针,没有尾结点指针的循环双链表
D. 既有头结点指针,又有尾结点指针的循环单链表
// 根据 “删除最后一个元素” 的特殊性(单链表要从头遍历),建议选择双链表;而 B 没有头,“删除第一个元素” 时要从尾遍历一遍到头
eg:已知表头元素为 c 的单链表在内存中的存储状态如下表:现将 f 存放于 1014H 处并插入单链表,若 f 在逻辑上位于 a 和 e 之间,则 a,e,f的“链接地址”依次是( )
地址 元素 链接地址 1000H a 1010H 1004H b 100CH 1008H c 1000H 100CH d NULL 1010H e 1004H 1014H
A. 1010H,1014H,1004H
B. 1010H,1004H,1014H
C. 1014H,1010H,1004H
D. 1014H,1004H,1010H
// 对应 “地址” 和 “链接地址” 发现 c 的 “地址”没有一个元素的 “链接地址” 接,所以 c 是头,该链表顺序:(1008H)c -> 去找(1000H) -> (1000H)a -> 去找(1010H) -> (1010H)e -> 去找(1004H) -> (1004H)b -> 去找(100CH) -> (100CH)d -> NULL;此时要在 a,e 间插入 f:①(1000H)a -> 去找(1010H) -> (1010H)e -> 去找(1004H);②用 1014H 存 f ;③ f 指向(1010H)e,a指向(1014H) f ;所以综上就变成:(1000H) a (1014H) -> (1014H) f (1010H) -> (1010H) e (1004H),所以a,e,f的“链接地址”依次是:1014H,1004H,1010H
eg:对于一个头指针为 head 的带头结点的单链表,判空条件为( );
对于一个不带头结点的单链表,判空条件为( );
A. head == NULL;
B. head -> next == NULL;
C. head -> next == head;
D. head != NULL;
// (带头)头指针 head 指向头节点,头结点的 next 域指向(head -> next)第一个元素结点:head -> next == NULL;
//(不带头)头指针 head 直接指向(head ==)第一个元素结点:head == NULL;
eg:在一个以 L 为头指针的单循环链表中,p 指针指向链尾的条件是( );
A. p -> next == L;
B. p -> next == NULL;
C. p -> next -> next == L;
D. p -> data== -1;
// 单循环链表的链尾不是空啊啊,是循环链表啊啊,又指回到头了 p -> next -> next == L;
eg:在循环链表中,将头指针改设为尾指针(rear)后,其首元结点和尾结点的存储位置分别为( );
A. rear 和 rear -> next -> next
B. rear -> next 和 rear
C. rear -> next -> next 和 rear
D. rear 和 rear -> next
// “将头指针改设为尾指针(rear)” 就是将指向头的指针,指向尾,首元结点就是rear -> next -> next (头 -> next );尾结点就是指针的位置 rear
eg:向一个有127个元素的顺序表中插入1个新元素,并保持原来顺序不变,平均要移动的元素个数为( );
A. 8
B. 63.5
C. 63
D. 7
// 顺序表有127个元素,枚举一下:假如在第一个位置上插入,则要移动127;在第二个位置上插入,则要移动126;...假如在最后一个位置上插入,则移动0;所以平均要移动的次数:(0+127)/2 = 63.5
.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具