线性表(2)
前言:顺序表的考察一出现,感觉和很多东西会挂勾:排序、查找所挂钩。因此,排序和查找也会需要继续输出。
顺序存储
- 数据结构代码
#define MAXSIZE 20
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE]; // 数组的存储数据元素
int length; // 线性表当前结构
}SqList;
-
地址计算
&a[n] = &a[0] + n*sizeof(a[0]);
-
时间复杂度
-
ListInsert (*L, i, e)
-
插入元素,需要移动大量的元素,平均移动次数 n − 1 2 \frac{n-1}{2} 2n−1个。
-
时间复杂度是 O ( n ) O(n) O(n)
-
抛出异常条件:插入位置不合理、线性表已满
-
代码逻辑✨
for (k = L->length - 1; k >= i - 1; k--) { L->data[k+1] = L->data[k]; } L->length ++;
-
-
ListDelete (*L, i, e)
-
删除元素,需要移动大量的元素,平均移动次数 n − 1 2 \frac{n-1}{2} 2n−1个。
-
时间复杂度是 O ( n ) O(n) O(n)
-
抛出异常条件:插入位置不合理(视删除位置而定)、线性表空
-
代码逻辑✨
for (k = i - 1; k <= length - 1; k++) { L->data[k] = L->data[k+1]; } L->length --;
-
-
常用算法
常用思想
- “设计一个时间上尽可能高效的算法”
- 空间复杂度,随意,搞高高
- 空间换时间
- 关键字范围:有可能利用桶排的思想
- 无序变有序
- 本身有序:查找的思想
原地逆置顺序表
空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( N ) O(N) O(N)
int reverse(int a[], int n)
{
int low = 0, high = n - 1;
for (int i = 0; i < n / 2; i ++ )
{
int mid;
mid = a[low];
a[low] = a[high];
a[high] = mid;
low++;
high--;
}
}
桶排(计数排序算法)
【2013年统考真题】
空间复杂度 O ( N ) O(N) O(N),时间复杂度 O ( N ) O(N) O(N)
int find_main_elem(int a[], int n)
{
int flag[n+1]={0};
int j = 0;
for (int i = 0; i < n; i++)
{
if(a[i]<0 || a[i]>n+1)// 其实题目已经说了0<= ai < n,可以不判
{
continue;
}
flag[a[i]]++;
}
while(a[j] <= (n/2))
{
j++;
}
return j;
}
多指针的扫描
【2011年统考真题:找中位数】
空间复杂度 O ( N ) O(N) O(N),时间复杂度 O ( N ) O(N) O(N): 但是,满分解并非是 O ( N ) O(N) O(N),而是 O ( log N ) O(\log N) O(logN)。满分解会在排序里介绍。
int find_main_elem(int s1[], int s2[], int L)
{
int mid_index = (L+1)/2 , p1 = 0, p2 = 0;
int now;
for (int i = 1; i <= mid_index; i++)
{
if(s1[p1] < s2[p2]) p1++, now = s1[p1];
if(s1[p1] >= s2[p2]) p2++, now = s2[p2];
}
return now;
}
int delete_x(List &L, int x)
{
if (L.empty())
return -1;
int i = 0, k = 0;
for (; i < L.length(); i++)
{
if (L[i] != x)
{
L[k] = L[i];
k++;
}
}
// k is the size of the L
L.length = k;
}