2023数据结构考研复习-线性表
Posted ZSYL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2023数据结构考研复习-线性表相关的知识,希望对你有一定的参考价值。
2023数据结构考研复习
前言
数据结构考研复习过程中记录部分代码学习,由于考研复习时间紧凑,就没有详细写注释跟笔记,请谅解。
2023考研必胜!
绪论
1. 对于两种不同的数据结构,逻辑结构或物理结构一定不相同吗?
数据运算也是数据结构的一部分。
对于两种不同的数据结构,它们的逻辑结构和物理结构完全有可能相同。比如二叉树和二叉排序树,之叉排序树可以采用二叉树的逻辑表示和存储方式,前者通常用于表示层次关系,而后者通常用于排序和查找。虽然它们的运算都有建立树、插入结点、删除结点和查找结点等功能,但对于二叉树和二叉排序树,这些运算的定义是不同的,以查找结点为例,二叉树的时间复杂度为O(n),而二叉排序树的时间复杂度为O(log2n)。
2. 试举一例,说明对相同的逻辑结构,同一种运算在不同的存储方式下实现时,其运算效率不同。
线性表既可以用顺序存储方式实现,又可以用链式存储方式实现。在顺序存储方式下,在线性表中插入和删除元素,平均要移动近一半的元素,时间复杂度为O(n);而在链式存储方式下,插入和删除的时间复杂度都是O(1)。
3. 递归方程
求递推方程。
4. 时间复杂度
- 循环主体中的变量参与循环条件的判断
此类题应该找出主体语句中与T(n)成正比的循环变量,将之代入条件中进行计算。 - 循环主体中的变量与循环条件无关
此类题可采用数学归纳法或直接累计循环次数。
5. 斐波那契数列
【你真的懂斐波那契数列吗?】Fibonacci四种解法满足你!
顺序表
#include <iostream>
using namespace std;
const int Initsize = 10;
struct Sqlist
int *data; // 指向第1个元素的地址
int maxsize;
int length;
;
void init(Sqlist &l)
l.data = new int[Initsize];
l.length = 0;
l.maxsize = Initsize;
void IncreaseSize (Sqlist &l, int len)
int *p = l.data;
l.data = new int[l.maxsize+len];
for (int i=0; i < l.length;i++)
l.data[i] = p[i];
l.maxsize = l.maxsize+len;
delete p;
bool insert(Sqlist &l, int i, int e)
if (l.length > l.maxsize)
for (int j = l.length; j >=i; j--)
l.data[j] = l.data[j-1];
l.data[i-1] = e;
l.length++;
return true;
bool delete (Sqlist &l, int i, int &e)
// &e保存删除值
int main()
Sqlist L;
init(L);
insert(L, 1, 1);
insert(L, 2, 2);
for (int i = 0; i < L.length;i++)
cout << L.data[i] << " ";
IncreaseSize(L, 5);
cout << L.maxsize <<'\\n';
cout << "Hello World";
return 0;
- 判断是否为空队列:
front == rear;
- 获取队列长度:
rear - front + queueArray.length) % queueArray.length;
- 判断是否满:
rear+1) % queueArray.length == front
- 队列清空:
front = rear = 0;
广义表
//定义广义表
//广泛的,普遍的,非具体的,整体的
class Node<T>
Node<T> hp; //指向表头
Node<T> tp; //指向表尾
T data; //存放单元素的数据域
int tag; //区分表结点和元素结点的标志 0:原子结点。1:表结点
// 原子结点的构造方法
public Node(int tag, T data)
this.tag = tag;
this.data = data;
//指针无指向,为空
hp = null;
tp = null;
/*
* 注意:除非空表的表头结点指针为空,对任何非空列表,其表头指针均指向一个表结点,
* 且该结点中的 hp 域指示列表表头(或者原子结点,或者为表结点)
* tp域指向列表尾(除非表为为空,则指针为空,否则为表结点)
*/
// 表结点的构造方法
public Node(int tag, Node hp, Node tp)
this.tag = tag;
this.hp = hp;
this.tp = tp;
综合应用题
1. 删除最小值
从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。
算法思想:搜索整个顺序表,查找最小值元素并记住其位置,搜索结束后用最后一个元素填补空出的原最小值元素的位置。
bool del_Min(sqList &L, int value)
if (L.length == 0)
return false;
value = L.data[0];
int pos = 0;
for (int i = 1; i < L.length; i++)
if (L.data[i] < value)
value = L.data[i];
pos = i;
L.data[pos] = L.data[L.length-1];
L.length--;
return value;
2. 链表逆置
设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1).
算法思想: 扫描顺序表L的前半部分元素,对于元素工.data [ i] (0<=i<L.length/2),将其与后半部分的对应元素L.data [L.length-i-1]进行交换。
void reverse(sqlList &L)
int temp;
for (int i = 0; i < L.length/2; i++)
temp = L.data[i];
L.data = L.data[L.length-i-1];
L.data[L.length-i-1] = temp;
3. 删除所有值为x的元素
对长度为n的顺序表L,编写一个时间复杂度为On)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为x的数据元素。
解法一:用k记录顺序表L中不等于x的元素个数(即需要保存的元素个数),扫描时将不等于x的元素移动到下标k的位置,并更新k值。扫描结束后修改L的长度。
void del_x(sqList &L, int x)
int k = 0;
for (int i = 0; i < L.length; i++)
if (L.data != x)
L.data[k++] = L.data[i];
L.length = k;
解法二:用k记录顺序表L中等于x的元素个数,边扫描L边统计k,并将不等于x的元素前移k个位置。扫描结束后修改L的长度。
void del_x(sqList &L, int x)
int k = 0, i = 0;
while (i < l.length)
if (L.data[i] == x)
k++;
else
L.data[i-k] = L.data[i];
i++;
L.length = lengthk;
此外,本题还可以考虑设头、尾两个指针(i= 1,jn),从两端向中间移动,在遇到最左端值x的元素时,直接将最右端值非x的元素左移至值为x的数据元素位置,直到两指针相遇。但这种方法会改变原表中元素的相对位置。
4. 删除指定范围数据
从有序顺序表中删除其值在给定值s与t之间(要求s <t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。
注意:本题与上一题存在区别。因为是有序表,所以删除的元素必然是相连的整体。算法思想:先寻找值大于等于s的第一个元素(第一个删除的元素),然后寻找值大于t的第一个元素(最后一个删除的元素的下一个元素),要将这段元素删除,只需直接将后面的元素前移。
bool del_s_t(SqlList &L, int s, int t)
int i, j;
if (s >= t || L.length == 0)
return 0;
for (i = 0; L.data[i] < s; i++)
if (i < L.length)
return 0;
for (j = 0; L.data[j] <= t; j++)
for (; j < L.; j++, i++)
L.data[i] = L.data[j];
L.length = i;
return 1;
5. 删除指定范围数据2
从顺序表中删除其值在给定值s与t之间(包含s和t,要求s <t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。
算法思想:从前向后扫描顺序表L,用k记录下元素值在s到t之间元素的个数(初始时k=0)。对于当前扫描的元素,若其值不在s到t之间,则前移k个位置;否则执行k++。由于这样每个不在s到t之间的元素仅移动一次,因此算法效率高。
bool Delst(SqList &L, ElemType s,ElemType t)//删除顺序表L中值在给定值s与t(要求s<t)之间的所有元素
int i, k = 0;
i(L.length == 0|| s >= t)
return false;
// 线性表为空或s、t不合法,返回
for(i = 0; i < L.length; i++)
if(L.data[i] >= s && L.data[i] <= t)
k++;
else
L.data[i-k] = L.data[i]; //当前元素前移k个位置
L.length -= k; //长度减小
return true;
void del_x(sqList &L, int s, int t)
int k = 0;
for (int i = 0; i < L.length; i++)
if (L.data[i] < s || L.data[i] > t)
L.data[k++] = L.data[i];
L.length = k;
注意:本题也可从后向前扫描顺序表,每遇到一个值在s到t之间的元素,则删除该元其后的所有元素全部前移。但移动次数远大于前者,效率不够高。
6. 有序表去重
从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。
算法思想:注意是有序顺序表,值相同的元素一定在连续的位置上,用类似于直接插入排序的思想,初始时将第一个元素视为非重复的有序表。之后依次判断后面的元素是否与前面非重复有序表的最后一个元素相同,若相同,则继续向后判断,若不同,则插入前面的非重复有序表的最后,直至判断到表尾为止。
与上面题目类似,维护一个指针指向第一个不相同的元素。
bool del_Same(SqlList &L)
if (L.length == 0)
return 0;
int i, j = 0;
for (int i = 0, j = 1; j < L.length; j++)
if (L.data[i] != L.data[j])
L.data[++i] = L.data[j];
L.length = j;
return 1;
合并有序表
将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。
算法思想:首先,按顺序不断取下两个顺序表表头较小的结点存入新的顺序表中。然后,看哪个表还有剩余,将剩下的部分加到新的顺序表后面。
bool merge(SqlList &A, SqlList &B, SqlList &C)
if (A.length + B.length > C.length)
return 0;
int i, j = 0, k = 0;
while (i < A.length && j < B.length)
if (A.data[i] < B.data[j])
C.data[k++] = A.data[i++];
else
C.data[k++] = B.data[j++];
while (i < A.length)
C.data[k++] = A.data[i++];
while (j < B.length)
C.data[k++] = B.data[j++];
c.length = k;
return 1;
7. 线性表位置互换
已知在一维数组A[m+n]中依次存放两个线性表(a1, a2, a3…, am)和(b1, b2, b3,.… bn),编写一个函数将数组中两个顺序表的位置互换。
算法思想:先将数组A[m+n]中的全部元素原地迎置,再对前n个元素和后m个元素分别使用逆置算法,从而实现顺序表的位置互换。
void reverse (int[] x, int l, int r)
if (l >= right || right > sizeof(x))
return;
int mid = (l+r) >> 1;
for (int i = 0; i <= mid-l; i++)
int temp = x[l+i];
x[l+i] = x[r-i];
x[l+i] = temp;
void exchange (int x[], int m, int n)
reverse (x, 0, m+n-1);
reverse (x, 0, n-1);
reverse (x, n, m+n-1);
9. 折半查找插入
线性表(a1,a2, a3,…,an)中的元素递增有序且按顺序存储于计算机内。要求设计一个算法完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。
void searchInsert(int[] a, int x)
int l = 0, h = sizeof(a)-1, mid;
while (l <= h)
mid = (l+h) >> 1;
if (a[mid] == x)
break;
else if (a[mid] < x)
l = mid+1;
else
h = low-1;
if (a[mid] == x && mid != n-1)
int t = a[mid];
a[mid] = a[mid+1];
a[mid+1] = t;
if (low > high)
for (int i = n-1; i > high; i--)
a[i+1] = a[i];
a[i+1] = x;
10. 循环左移
设将n (n >1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p (0<p<n)个位置。要求:
- 1)给出算法的基本设计思想。
- 2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
- 3)说明你所设计算法的时间复杂度和空间复杂度。
可将这个问题视为把数组ab转换成数组ba(a代表数组的前p个元素,b代表数组中余下的p个元素),对abcdefgh向左循环移动3 (p = 3)个位置的过程如下:
- Reverse(0 , p-1)得到cbadefgh;
- Reverse(p , n-1)得到cbahgfed;
- Reverse(0 , n-1)得到defghabc;
- 注:Reverse 中,两个参数分别表示数组中待转换元素的始末位置。
void Reverse(int[] r, int fron, int end)
int i, temp;
for (int i = 0; i < (from+end)>>1; i++)
temp = r[from+i];
r[from+i] = r[end-i];
r[end-i] = temp;
void Converse(int r[], int n, int p)
Reverse(r, 0, p-以上是关于2023数据结构考研复习-线性表的主要内容,如果未能解决你的问题,请参考以下文章