2024王道数据结构 大题01-线性表的顺序存储

//
// Created by Yue on 2023-08-31.
//

#ifndef INC_2_2_1_SQLLIST_H
#define INC_2_2_1_SQLLIST_H

#define MaxSize 50
typedef  int ElemType;
typedef struct {
    ElemType data[MaxSize];
    int length;
}SqlList;

// 插入一个新元素e, i 为位序
bool ListInsert(SqlList &L,int i, ElemType e)
{
    if(i < 1 || i>L.length+1){
        return false;
    }
    if (L.length >= MaxSize){
        return false;
    }
    // 依次往后移动元素
    for(int j=L.length;j>=i;j--){
        L.data[j] = L.data[j-1];
    }
    L.data[i-1] = e;
    L.length++;
    return true;
}

// 删除操作,给定位序i,删除对应位序i上的元素,并用e将值带回来
bool ListDelete(SqlList &L,int i,ElemType &e){
    if (i <= 1 || i >L.length)
        return false;
    e = L.data[i-1];
    for (int j=i-1;j<L.length-1;j++){
        L.data[j] = L.data[j+1];
    }
    L.length--;
    return true;
}
// 按值查找
int LocateElem(SqlList L,ElemType e){
    for(int i=0;i<L.length;i++){
        if(L.data[i] == e){
            return i+1;
        }
    }
    return 0;
}
// 按位查找
ElemType GetElem(SqlList L,int i){
    return L.data[i-1];
}
// 2.2.3 第1题 删除最小值的元素,并由函数返回被删除的值。空出的位置由最后一个元素填补
bool DeleteMin(SqlList &L,ElemType &value){
    if (L.length <= 0)
        return false;
    ElemType min=L.data[0];
    int minIndex=0;
    for(int i=1;i<L.length;i++){
        if (L.data[i] < min){
            min = L.data[i];
            minIndex = i;
        }
    }
    L.data[minIndex] = L.data[L.length-1];
    L.length--;
    value = min;
    return true;
}
// 第2题设置一个高效的算法,将顺序表L的所有元素逆置,要求空间复杂度为O(1)
void ListReverse(SqlList &L){
    for(int i=0;i<L.length/2;i++){
        ElemType temp = L.data[i];
        L.data[i] = L.data[L.length-1-i];
        L.data[L.length-1-i] = temp;
    }
}
// 第3题 删除线性表中所有值为x的元素,要求时间复杂度为O(n)
void ListDeleteElemX(SqlList &L,ElemType x){
    // 思路:扫描一遍有多少个x
    int count=0;
    for (int i =0;i<L.length;i++){
        if (L.data[i] == x){
            count++;
        }else{
            L.data[i-count] = L.data[i];
        }
    }
    L.length = L.length - count;
}
//第4题 从有序顺序表中删除其值在 s 与 t之间的所有元素
bool DeleteFromOrderedBetweenST(SqlList &L,ElemType s,ElemType t){
    if(L.length == 0 || s>=t)
        return false;
    int firstS=-1;
    int firstT=-1;
    for (int i = 0;i<L.length;i++) {
        if (L.data[i] >= s) {
            firstS = i;
            break;
        }
    }
    for(int j=firstS;j<L.length;j++){
        if(L.data[j] > t){
            firstT = j;
            break;
        }
    }
    if(firstS >= L.length)
        return false;
    int k = 0;
    for(int j = firstT;j<L.length;j++){
        L.data[firstS+k]= L.data[j];
        k++;
    }
    L.length = firstS+k; // 之前写的firstT-firstS+1想想什么问题
    return true;
}
// 第4题 王道书中给出的代码
bool DeleteFromOrderedBetweenST(ElemType s,ElemType t,SqlList &L) {
    // 删除有序顺序表L在给定值s与t之间的所有元素
    if(s >= t || L.length == 0)
        return false;
    int i,j;
    for(i=0; i<L.length && L.data[i] < s;i++); // 找的是第一个要删除的
    if(i >= L.length)
        return false;
    for(j=i;j<L.length && L.data[j] <= t;j++);  //找的是第一个不删除的
    for (;j<L.length;j++,i++)
        L.data[i] = L.data[j];
    L.length = i;
}
// 第5题  从顺序表中删除其值在给定值s 与 t之间(包含s和t,要求s<t)的所有元素
bool DeleteBetweenST(SqlList &L,ElemType s,ElemType t){
    if (L.length == 0 || s >= t)
        return false;
    // 沿用上一问的思路
    // 或者记录不处于这个区间的个数
    int count = 0;
    for (int i = 0;i<L.length;i++){
        if (L.data[i] < s || L.data[i] >t){
            count ++;
            L.data[count-1] = L.data[i];
        }
    }
    L.length = count;
}

// 第6题 从有序表中删除其值重复的元素,使表中所有元素的值均不同
bool DeleteRepeatValue(SqlList &L){
    if(L.length == 0)
        return false;
    if(L.length == 1)
        return true;
    int i,j;
    int count=1;
    for(i=1;i<L.length;i++){
        if(L.data[i-1] != L.data[i]){
            count++;
            L.data[count-1] = L.data[i];
        }
    }
    L.length = count;
    return true;
}
// 王道书中的代码,虽然不太懂,但是妙啊
bool DeleteSame(SqlList &L){
    if(L.length == 0)
        return false;
    int i,j;    // i存储第一个不相同的元素,j为工作指针
    for(i=0,j=1;j<L.length;j++){
        if(L.data[i] != L.data[j])  // 查找下一个与上一个元素值不同的元素
            L.data[++i] = L.data[j]; // 找到后将元素前移  // 相当于i保存了处理过的,在i之前的都是不重复的
    }
    L.length = i+1;
    return true;
}
// 第7题 两个有序顺序表合并成一个新的有序顺序表
bool MergeTwoSorted(SqlList M,SqlList N,SqlList &C){
    if (M.length + N.length > MaxSize){
        return false;
    }
    // 思想: 按顺序比较两个有序表中的元素,每次将较小的元素放入新的有序表里
    int i=0,j=0;
    int k=0;
    while(i<M.length && j <N.length){
        if (M.data[i] <= N.data[j]){
            C.data[k++] = M.data[i];
            i++;
        }else{
            C.data[k++] = N.data[j];
            j++;
        }
    }
    while(i<M.length){
        C.data[k++] = M.data[i++];
    }
    while(j<N.length){
        C.data[k++] = N.data[j++];
    }
    C.length = k;
    return true;
}
bool Merge(SqlList A,SqlList B,SqlList &C){
    if(A.length + B.length > MaxSize)
        return false;
    int i=0,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+1;
    return true;
}
// 第8题 已知在一维数组A[m+n]中依次存放两个线性表。编写一个函数将两个线性表的位置互换
// 先逆置所有的,再逆置前n个,再单独逆置后m个
void ReverseArrayA(ElemType A[],int m,int n){
    int i=0,j=m;
    for(int i=0;i<(m+n)/2;i++){
        ElemType temp = A[i];
        A[i] = A[m+n-1-i];
        A[m+n-1-i] = temp;
    }
    // 再逆置前n个
    for(int i=0;i<n/2;i++){
        ElemType temp = A[i];
        A[i] = A[n-1-i];
        A[n-1-i] = temp;
    }
    // 逆置后m个
    for(int i=n;i<=(2*n+m-1)/2;i++){
        ElemType temp = A[i];
        A[i] = A[2*n+m-1-i];
        A[2*n+m-1-i] = temp;
    }
}
typedef int DataType;
void Reverse(DataType A[],int left,int right,int arraysize){
    // 逆转
    if (left >= right || right >= arraysize)
        return;
    int mid = (left+right)/2;
    for(int i=0; i<= mid-left;i++){
        DataType temp = A[left+i];
        A[left+i] = A[right-i];
        A[right-i] = temp;
    }
}
void Exchange(DataType A[],int m,int n,int arraysize){
    Reverse(A,0,m+n-1,arraysize);
    Reverse(A,0,n-1,arraysize);
    Reverse(A,n,m+n-1,arraysize);
}
// 第9题 线性表递增有序,最少时间在表中查找值为x的元素。若找到,将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍然有序
void SearchAndInsert(SqlList &L,ElemType x){
    // 首先使用二分查找
    int low = 0,high = L.length-1,mid;
    while(low <= high){
        mid = (low+high) / 2;
        if(L.data[mid] == x) break;
        else if(L.data[mid] > x) high = mid -1;
        else if(L.data[mid] < x) low = mid +1;
    }
    if(low > high){
        // 未找到该元素,此时low一定指向第一个大于x的位置
        for(int i=L.length;i>low;i--){
            L.data[i] = L.data[i-1];
        }
        L.data[low] = x;
        L.length ++;
    }
    else if (mid != L.length-1){ // x不是最后一个元素,交换位置
        int temp = L.data[L.length-1];
        L.data[L.length-1] = x;
        L.data[mid] = temp;
    }
}
// 第10题 将数组循环左移p位
// 自己做不出来,看答案
void CircleMoveP(int p,int A[],int n){
    // 可以将问题视为将数组ab, 转换成数组ba
    // a 代表数组前p个元素,b 代表数组余下的n-p个元素
    // 首先将整个数组逆置,再分别对前n-p个元素 、后p个元素进行逆置
    // 即可得到数组ba
    int i=0;
    for(int i=0;i<n/2;i++){
        ElemType temp = A[i];
        A[i] = A[n-1-i];
        A[n-1-i] = temp;
    }
    // 再逆置前n-p个
    for(int i=0;i<(n-p)/2;i++){
        ElemType temp = A[i];
        A[i] = A[n-p-1-i];
        A[n-p-1-i] = temp;
    }
    // 逆置后p个
    for(int i=n-p;i<(2*n-p)/2;i++){
        ElemType temp = A[i];
        A[i] = A[2*n-p-1-i];
        A[2*n-p-1-i] = temp;
    }
}

// 第11题 求两个等长s升序序列的中位数
ElemType MediumOfTwoLinearList(SqlList M,SqlList N){
    if(M.length != N.length || M.length == 0)
        return -1;
    // 我的思路:按照归并思路的方式,当取到第中间位置的元素时就返回
    int i=0,j=0,count=0;
    int temp = 0;
    while(i<M.length && j<N.length){
        if (M.data[i] <= N.data[j]){
            temp = M.data[i];
            i++;
        }else{
            temp = N.data[j];
            j++;
        }
        count++;
        if (count == M.length){
            return temp;
        }
    }
}
// 王道书中的算法不理解

// 第12题 找主元素
// 思路: 第一遍扫描两两抵消掉不同的元素,最后留下的元素可能是主元
// 再第二遍扫描,计算是否大于n/2
bool FindPivotElement(int A[],int n,int &p){
    if (n == 1)
        return A[0];
    int pivot = A[0],i=1;
    int count = 1;
    for(;i<n;i++){
        if(A[i] == pivot){
            count++;
        }else{
            count--;
            if (count == 0){
                pivot = A[i];
                count = 1;
            }
        }
    }
    count = 0;
    // 再一遍扫描计算pivot的个数
    for(int i=0;i<n;i++){
        if(pivot == A[i]){
            count++;
        }
    }
    if(count > n/2){
        p = pivot;
        return true;
    }else{
        return false;
    }
}
// 暴力做法
bool FindPivotElement(int A[],int &p,int n){
    int *arr = (int *) malloc(sizeof (int)*n);
    for (int i=0;i<n;i++){
        int temp = A[i];
        int count = 0;
        for(int j=0;j<n;j++){
            if(A[j] == temp){
                count++;
            }
        }
        if(count > n/2){
            p = temp;
            return true;
        }
    }
    return false;
}

// 第13题 寻找最小未出现的正整数
// 在时间上尽可能高效————以空间换时间
int FindMinDisappear(int A[],int n){
    int *temparr = (int *) malloc(sizeof (int )*n);
    for(int i=0;i<n;i++)
        temparr[i] = 0;
    for(int i=0;i<n;i++){
        if(A[i]>0 && A[i] <= n)
            temparr[A[i]-1] = 1;
    }
    for(int i=0;i<n;i++){
        if(temparr[i] == 0){
            return i+1;
        }
    }
    return n+1;
}
// 暴力做法 时间复杂度 O(n^2) 空间复杂度O(1)
bool FindDisappearMinInt(int A[],int n,int &e){
    int temp = 1;
    while(true){
        bool appear = false;
        for(int i=0;i<n;i++){
            if(A[i] == temp){
                appear = true;
                break;
            }
        }
        if(appear == false){
            e = temp;
            return true;
        }else{
            temp++;
        }
    }
}

// 第14题 输出所有可能三元组中的最小距离
// 注意给的条件中S1,S2,S3都是升序的

// D = 2*{max(a,b,c) - min(a,b,c)}
// 改变min(a,b,c) 是一个最优策略,因为往后遍历a b c 都只会往D增大的方向改变
#define INT_MAX 0x7fffffff

// 找到三个数中最小数的下标 如果最小的是a 返回1,最小的是b返回2...
int MinOfThreeNums(int a,int b,int c){
    if(a <= b && a <= c){       // 注意这里带 等号! 否则死循环!!!
        return 1;
    }else if(b <= a && b <= c){
        return 2;
    }else{
        return 3;
    }
}

int MinDistanceOfTriTuple(int S1[],int m,int S2[],int n,int S3[],int p){
    int i=0,j=0,k=0;
    int D_min = INT_MAX;
    int D;
    while(i<m && j<n && k<p){
        D = abs(S1[i]-S2[j])+ abs(S1[i]-S3[k]) + abs(S2[j]-S3[k]);
        if(D < D_min){
            D_min = D;
            // 找到此时三个数中最小的数的下标,将最小的数的下标右移
            int min_index = MinOfThreeNums(S1[i],S2[j],S3[k]);
            if(min_index == 1) i++;
            else if(min_index == 2) j++;
            else k++;
        }
    }
    return D_min;
}

// 打印顺序表
void ListPrint(SqlList L){
    cout<<L.length<<endl;
    for (int i = 0;i < L.length;i++)
        cout<<L.data[i]<<"  ";
    cout<<endl;
}

#endif //INC_2_2_1_SQLLIST_H

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值