:::danger
顺序表的基本操作:
InitList(&L);//初始化表
LocateElem(L,e);//按照值查找,在表L中查找e元素
GetElem(L,i);//按照索引查找,获取表L中第i个元素
ListInsert(&L,i,e);//插入操作,在表L的第i个位置插入元素e
ListDelete(&L,i,&e);//删除操作,删除表L中第i个位置的元素,将删除的元素放到e中
PrintfList(L);//打印表L
DestroyList(&L);//销毁表L
:::
一:顺序表的定义以及CURD
1.顺序表定义
表中元素的逻辑顺序与其物理顺序相同
顺序表 | 索引 |
---|---|
a1 | 0 |
a2 | 1 |
a3 | 2 |
…… | …… |
分配一块连续的内存去存放这些元素,例如:数组
#include <stdio.h>//库函数
#include <stdlib.h>//库函数
#define MAXLIST 6//用于静态定义的数组长度
#define true 1
#define false 0
2.结构体的定义
静态分配:
typedef struct {
int arr[MAXLIST];//首地址
int size;//数组中数据的实际长度
}SqList;
-------------------------------------------
动态分配:
typedef struct {
int *arr;//首地址
int length;//当前长度,数组的长度
int size;//数组中数据的实际长度
}SqList;
3.顺序表的初始化
void InitList(SqList *L){
L->arr = (int*)malloc(MAXLIST*sizeof(int));
//刚初始化时,数组中元素的内容为0
L->size = 0;
//数组的最大长度为MAXLIST
L->length = MAXLIST;
}
4.顺序表的查找操作
按照索引查找元素
int GetElem(SqList *L,int i){
//如果要插入的索引非法,则提示出错
if(i>=L->length&&i<0){
printf("error");
}
return *((L->arr+i)-1);
}
按照元素查找索引
int LocateElem(SqList *L,int e){
for(int i = 0;i<L->size;i++){
//只要找到了就返回
if(*(L->arr+i)==e){
return i;
break;
}
}
//如果没找到就返回-1
return -1;
}
5.顺序表的插入操作
时间复杂度最好情况:O(1)
时间复杂度最坏情况:O(n)
时间复杂度平均情况:n/2–>O(n)
//在表L中的第i个位置插入data元素
void ListInsert(SqList *L,int i,int data){
//如果要插入的索引非法,则提示出错
if(i>=L->length&&i<0){
printf("error");
}
int*q,*p;
//先找到要插入的位置
q = (L->arr)+i-1;
//找到数组中最后一个数据的位置
p = (L->arr)+(L->size);
//从要插入的位置q到最后一个元素,依次向后移动1位
for(;p>=q;p--){
*(p+1) = *p;
}
//腾出插入的空间后,插入元素
*q = data;
//数组元素个数+1
L->size++;
}
6.顺序表的删除操作
时间复杂度最好情况:O(1)
时间复杂度最坏情况:O(n)
时间复杂度平均情况:n-1/2—>O(n)
void ListDelete(SqList *L,int i,int &e){
int *p,*q;
//先找到删除的位置
q = L->arr+i-1;
//将要删除的元素存起来
e = *q;
//找到数组中最后一个数据的位置
p = L->arr+L->size;
//依次向前挪动1位
for(;q<=p;q++){
*q = *(q+1);
}
//数组元素个数-1
L->size--;
}
7.顺序表的打印操作
void printList(SqList *L){
for(int i = 0;i<L->size;i++){
printf("%d->",*((L->arr)+i));
}
printf("NULL\n");
}
二:线性表综合应用题(王道)
能力有限,只写了会写的题目。
- 从顺序表中删除具有最小值的元素(假设唯一) 并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。
思路:
1.循环遍历找到最小值
2.按题目要求删去最小值
void delMin(SqList *L){
//用来记录最小的值是多少
int min =L->arr[0];
//用来记录最小值的索引
int minIndex = 0;
//循环遍历寻找最小值
for(int i = 1;i<L->size;i++){
if(min>L->arr[i]){
minIndex = i;
min = L->arr[i];
}
}
//按照题目要求删除最小值
L->arr[minIndex] = L->arr[L->size-1];
}
- 设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为 O(1).
思路:
1.双指针,首尾各一个
2.首指针向后移动,尾指针向前移动
void Reverse(SqList *L){
for(int i = 0,j = L->size-1;i<j;i++,j--){
int temp = L->arr[i];
L->arr[i] = L->arr[j];
L->arr[j] = temp;
}
}
- 对长度为n的顺序表L,编写一个时间复杂度为 O(n)、空间复杂度为 O(1)的算法,该算法删除线性表中所有值为 x 的数据元素。
思路:
1.寻找指定元素
2.设置一个尾指针
3.只要找到了指定元素,就将尾指针的元素覆盖掉指定元素
4.覆盖完毕后,尾指针向前移动一位
void delByX(SqList *L,int x){
//q指向首元素,p指向尾元素
int *q,*p,k=L->size-1;
// 如果,发现要删除的元素,
// 让其与末尾元素互换,然后元素个数-1
for( q = L->arr,p = L->arr+k;q<p;q++){
if(*q==x){
*q = L->arr[k];
k--;
}
}
L->size = k;
}
- 从有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,若s或!不合理或顺序表为空,则显示出错信息并退出运行
思路:
1.这个题和上一个题,思路相似,只不过这个不仅仅是删除指定元素
2.删除指定的两个元素之间的所有数据
3.首先找到两个指定元素
4.然后删除两个指定元素之间的数据
void delBys_t(SqList *L,int s,int t){
int *q,*p;
for(int i = 0;i<L->size;i++){
if(L->arr[i]==s){
q = L->arr+i;
}
if(L->arr[i]==t){
p = L->arr+i;
}
}
for(;q<p& p<L->arr+(L->size-1);q++,p++){
*q = *(p+1);
L->size--;
}
}
- 从顺序表中删除其值在给定值s与t之间 (包含s和t,要求 s<t)的所有元素,若s或t 不合理或顺序表为空,则显示出错信息并退出运行
同题4
- 从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同
思路:(此方法只适用于有序的顺序表)
1.快慢指针:两两比较
2.如果两者所指元素不等,就将慢指针后移,然后将快指针的内容赋值到慢指针所指
3.快指针每次遍历都要移动
void Del_Same(SqList *L){
int *slow = L->arr;
int *fast = L->arr+1;
for(int i = 0;i<L->size;i++){
if(*slow!=*fast){
slow++;
*slow = *fast;
L->size--;
}
fast++;
}
}
- 将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。
思路:
0.默认两个有序顺序表位升序的
1.创建一个新的数组空间,大小为两个顺序表的长度
2.然后循环遍历,选择其中一个顺序表位基础,与另一个顺序表作比较
3.比较过程中,谁小就把谁插入新的顺序表中
4.再比较过程中,其中一个顺序表为空了,就直接把另一个顺序表插入到新的顺序表中
void Merge(SqList *A,SqList *B,SqList *C){
//严谨性判断
if(A->size+B->size>C->size){
return;
}
int i = 0,j=0,k = 0;
for(;k<C->size;k++){
//如果A表空了,就把B表剩下的,插入C表
if(A->arr[i]==NULL){
C->arr[k] = B->arr[j];
}
//如果B表空了,就把A表剩下的,插入C表
if(B->arr[j]==NULL){
C->arr[k] = A->arr[i];
}
//如果B表中的元素更小,就将B表中的元素插入C表
if(A->arr[i]>B->arr[j]){
C->arr[k] = B->arr[j];
j++;
} else{
//否则就是A表中的元素更小,将A表中的元素插入C表
C->arr[k]=A->arr[i];
i++;
}
}
}
- 已知在一维数组A[m+n]中依次存放两个线性表(aa,as,”,am)和(b,b2,b;,bn)。编写一个函数,将数组中两个顺序表的位置互换,即将(bibz,b,b)放在(a,2,a3,am)的前面
思路:
举个例子:
1.A[10,20,30,40,11,21,31,41]--------变成------->[41,31,21,11,40,30,20,10]
2.A[41,31,21,11,40,30,20,10] 前n个元素自我逆置,后m个元素自我逆置
思路:
1.定义一个逆置方法,参数有,需要逆置的线性表、逆置的起始位置、逆置的终止位置
2.整体逆置阶段:参数为当前的线性表,0,L->size-1
3.前n个元素逆置阶段:参数为当前的线性表,0,n-1
4.后m个元素逆置阶段:参数为当前的线性表,L-size-m,L-size-1
void Reverse(SqList *L,int start,int end){
for(int i = 0;i<(end-start)/2;i++){
int temp = L->arr[start+i];
L->arr[start+i] = L->arr[end-i-1];
L->arr[end-i-1] = temp;
}
}
void Exchange(SqList *L,int n,int m){
//安全性判断
if(m>L->size||n<0){
return;
}
//整体逆置
Reverse(L,0,L->size-1);
//前n个元素逆置
Reverse(L,0,n-1);
//后数m个元素逆置
Reverse(L,L->size-m,L->size-1);
}
- [2010 统考真题]设将 n(n>1)个整数存放到一维数组 R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(O<p<n)个位置,即将R中的数据由(Xo,X,X-i)变换为(X,X+,X-1,Xo,X-i)。要求:
-
- 给出算法的基本设计思想。
- 根据设计思想,采用 C或 C++或 Java 语言描述算法,关键之处给出注释
-
- 说明你所设计算法的时间复杂度和空间复杂度。
-
同题8
- [2013 统考真题]已知一个整数序列A=(a0,a1,”,an-1),其中0<=ai<n(0<=i<n)。若存在ap1=ap2=……=apm=x且m>n/2(0<pk<n,1< k<=m),则称x为A的主元素。例如A=(0,5,5,3,5,7,5,5),则5为主元素;又如A=(0,5,5,3,5,1,5,7),则A中没有主元素。假设 A 中的 n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A 的主元素。若存在主元素,则输出该元素;否则输出-1。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用 C或 C++或 Java 语言描述算法,关键之处给出注释
3)说明你所设计算法的时间复杂度和空间复杂度。
思路:就是说,给了一个数组,如果数组中某个元素出现的次数大于该数组长度的一半,则称该元素为主元素
1.题目中说了,元素大小不超过数组长度,所以可以创建一个临时数组
2.遍历原数组,临时数组中记录元素出现的次数
3.找出临时数组中的最大值
4.若最大值大于数组的一半,则称为主元素;反则,没有主元素
int Majority(SqList *L,int n){
int maxValue=0;
int textArr[n];
for(int i = 0;i<n;i++){
textArr[L->arr[i]]++;
}
int max = textArr[0];
for(int i = 1;i<n;i++){
if(textArr[i]>max){
max = textArr[i];
maxValue = i;
}
}
if(max>=n/2){
return maxValue;
} else{
return -1;
}
}
- [2018 统考真题]给定一个含 n(n>=1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3)中未出现的最小正整数是 1;数组1,2,31中未出现的最小正整数是4。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用 C或 C++语言描述算法,关键之处给出注释
3)说明你所设计算法的时间复杂度和空间复杂度
思路:
1.用一个数组记录出现的数
2.将出现的数的所对应的索引置为1,未出现的数默认为0
3.循环遍历这个数组,寻找第一个为0的位置
int findMissMin(SqList *L,int n){
int minNum;
//初始化一个数组,用来存储出现的元素
int temp[]={0,0,0,0,0,0,0};
for(int i=0;i<n;i++){
//若元素为负数,则直接跳过
if(L->arr[i]<0){
continue;
}
//如果当前元素第一次出现,则记录在数组中
if(temp[L->arr[i]]!=1) {
temp[L->arr[i]] = 1;
}
}
//循环遍历当前数组
for(int i=0;i<n;i++){
//寻找第一个为0的元素对应的索引值
if(temp[i]==0){
minNum = i;
//找到后终止
break;
}
//若之前没有被终止,则说明是“123”这种情况
//所以,最小值就是4(最后一个元素值+1)
if(temp[n-1]!=0){
minNum = n;
}
}
return minNum;
}