数据结构之顺序表

:::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.顺序表定义

表中元素的逻辑顺序与其物理顺序相同
顺序表索引
a10
a21
a32
…………

分配一块连续的内存去存放这些元素,例如:数组

#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. 从顺序表中删除具有最小值的元素(假设唯一) 并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。

思路:
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];
}
  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;
    }
}
  1. 对长度为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;
}
  1. 从有序顺序表中删除其值在给定值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--;
    }
}
  1. 从顺序表中删除其值在给定值s与t之间 (包含s和t,要求 s<t)的所有元素,若s或t 不合理或顺序表为空,则显示出错信息并退出运行
同题4
  1. 从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同

思路:(此方法只适用于有序的顺序表)
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++;
    }
}
  1. 将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。

思路:
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++;
        }
    }
}
  1. 已知在一维数组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);
}
  1. [2010 统考真题]设将 n(n>1)个整数存放到一维数组 R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(O<p<n)个位置,即将R中的数据由(Xo,X,X-i)变换为(X,X+,X-1,Xo,X-i)。要求:
      1. 给出算法的基本设计思想。
    1. 根据设计思想,采用 C或 C++或 Java 语言描述算法,关键之处给出注释
      1. 说明你所设计算法的时间复杂度和空间复杂度。
同题8
  1. [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;
    }
}
  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;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱无盐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值