1. 1 线性表的顺序表示

/* 
    顺序表
 */
#include<iostream>
//clang.diagnostic.enable
using namespace std;

#define MaxSize 50
#define InitSize 100

typedef struct{
    ElemType data[MaxSize];
    int length;
}SqList;

typedef struct{
    ElemType *data;
    int MaxSize, length;
}SeqList;

InitList(&L);
Length(L);
LocateElem(L, e);
GetElem(L, i);
ListInsert(&L, i, e);
ListDelete(&L, i, &e);  //e 返回被删除元素的值
PrintList(L);
Empty(L);
DestroyList(&L);

/* 1. 顺序表中删除最小元素(唯一),并由函数返回被删除的元素, 用最后一个元素代替被删除的元素 */
bool Min_Dele(SqList &L, int &value){
    //删除顺序表L中的最小元素节点,并通过引用参数value返回其值
    //表空返回false, 删除成功返回true
    if (L.length == 0)
        return false; 
    value = L.data[0];
    int pos = 0;        //标记最小元素位置
    for (int i = 0; i < L.length; i++)  //遍历,找出最小值
        if (L.data[i] < value){
            value = L.data[i];      //更新value
            pos = i;                //更新pos
        }
    L.data[pos] = L.data[L.length - 1];     //最后元素补上空出位置
    L.length--;
    return true;
}

/* 2. 逆置顺序表,要求空间复杂度为 O(1) */
void Reverse(SqList &L){
    for (int i = 0; i < L.length / 2, i++)
        swap(L.data[i], L.data[L.length - 1 - i]);  //交换
}

/* 3. 删除长度为 n 的线性表 L 中所有值为 x 的元素, 要求 O(n), S(1) */
void Dele_x(SqList &L, int x){
    int k = 0;      //记录不等于 x 元素的个数
    for (int i = 0; i < L.length; i++)
        if (L.data[i] != x){
            L.data[k] = L.data[i];
            k++;
        }
    L.length = k;
}

/* 4. 删除有序顺序表中元素值在给定 s 与 t (s<t)之间的所有元素, s 或 t 不合理或顺序表为空,
则显示错误信息并返回 */
bool Dele_s_t(SeqList &L, int s, int t){
    if (s >= t || L.length == 0)
        return false;
    int i, j;
    for (i = 0; i < L.length && L.data[i] < s; i++);    //寻找 >= s 的第一个数 
    if (i >= L.length) return false;        //所有元素均 < s 返回
    for (j = i, j < L.length && L.data[j] <= t; j++);   //寻找 > t 的第一个数
    for ( ; j < L.length; j++)
        L.data[i++] = L.data[j];        //前移,填补被删除的数
    L.length = i;
    return true;
}

/* 5. 删除顺序表中元素值在给定 s 与 t (s<t)之间的所有元素, s 或 t 不合理或顺序表为空,
则显示错误信息并返回 */
bool Dele_s_t(SqList &L, int s, int t){
    int k = 0;   //k 为元素值不在s,t之间元素的个数
    if (s >= t || L.length == 0)
        return false;
    for (int i = 0; i < L.length; i++)
        if (L.data[i] < s || L.data[i] > t){
            L.data[k] = L[i];
            k++;
        }
    L.length = k;
    return true;
}

/* 6. 有序顺序表中删除所有值重复的元素 */
bool Dele_Same(SqList &L){
    if (L.length == 0) return false;
    int k = 0;      //记录不重复的元素值的元素的个数
    for (int i = 0; i < L.length; i++){
        L.data[k] = L.data[i];
        k++;
        while(i+1 < L.length && L.data[i] == L.data[i+1])
            i++;
    }
    L.length = k;
    return true;
}

/* 7. 将两个有序表合成一个新的有序表, 并返回该顺序表*/
bool Merge(SqList A, SqList B, SqList &L){
    if (A.length + B.length > L.Maxsize) return false;      //大于线性表的最大长度
    int i = 0, j = 0, k = 0;
    while (i < A.length && j < B.length){       //循环,比较,较小的存入结果表
        if (A.data[i] < B.data[j])
            L.data[k++] = A.data[i++];
        else
            L.data[k++] = B.data[j++];
    }
    while (i < A.length)        //将剩余的元素加入结果表
        L.data[k++] = A.data[i++];
    while (j < B.length)
        L.data[k++] = B.data[j++];
    L.length = k;
    return false;
}

/* 8. 一维数组A[m+n]中依次存放两个线性表(a1, ... ,am )和(b1, ... ,bn),
要求将数组中的两个线性表位置互换 */
void Reverse(int A[], int left, int right){
    if (left >= right)
        return;
    int mid = (left + right) / 2;
    for (int i = 0; i < mid - left; i++)
        swap(a[left+i], a[right-i]);
}
void Exchange(int A[], int m, int n){
    Reverse(A, 0, m+n-1);
    Reverse(A, 0, n-1);
    Reverse(A, n, m+n-1);
}

/* 9. 递增线性表,最少时间内从中查找出值为 x 的元素,然后将其与后继元素互换,如果找不到,就按序插入表中 */
void Search_Exchange_Insert(int A[], int x, int n){     // n 为线性表长度
    int left = 0, right = n-1, mid;
    while(left <= right){
        mid = (left + right) / 2;
        if (x < A[mid])
            right = mid - 1;
        else 
            left = mid + 1;
    }
    if (A[mid] == x && mid != n - 1)
        swap(A[mid], A[n-1]);
    if (left > right){
        for (int i = n-1; i > right; i--)
            A[i+1] = A[i];
        A[left] = x;
    }
}

/* 10. 将 R 一维数组中保存的序列循环左移 p 个位置 (A0, A1, ..., An) --> (Ap, ..., An, A0, ...,Ap-1)*/
/* 
    基本设计思想:(此题实际上就上第8题)
        该问题可视为将数组 ab 转成 ba,先将 ab 整体逆置为b-1 a-1,然后再分别逆置 b-1 , a-1
*/
void Reverse(int R[], int left, int right){
    for (int i = 0; i <= (right - left)/2; i++)
        swap(R[left+i], R[right-i]);
}
void Converse(int R[], int n, int p){
    Reverse(R, 0, n-1);
    Reverse(R, 0, p-1);
    Reverse(R, p, n-1);
}
/* 
    三个Reverse的时间复杂度分别为O(n/2), O(p/2), O( (n-p)/2 ).
    该算法的时间复杂度为O(n), 空间复杂度为O(1)
*/


/* 11. 找到两个等长上升序列 merge 的中位数 */
/* 
    设计思想:分别求两个升序序列A,B的中位数,记为a,b。求中位数的过程如下:
    1. 若 a = b, 则a 或 b 即为所求中位数;
    2. 若 a < b, 则舍弃 A 中较小的一半 和 B 中较大的一半,要求舍弃的长度一致;
    3. 若 a > b, 则舍弃 B 中较小的一半 和 A 中较大的一半,要求舍弃的长度一致;
    在保留的两个升序序列中重复 1,2,3过程,直到两个序列中只含一个元素时,较小者即为所求的中位数
*/
int Mean(int A[], int B[], int n){
    int a, b, aL = 0, aR = n-1, bL = 0, bR = n-1;       //分别表示A,B的中位数,首位数和末位数的下标
    while(aL < aR || bL < bR){
        a = (aL + aR) / 2;
        b = (bL + bR) / 2;
        if (A[a] == B[b]) return A[a];  //满足条件 1
        if (A[a] < B[b]){       //满足条件2
            if ((aL + aR) % 2 == 0){     //如果个数为奇数
                aL = a;         //舍弃 A 中间点之前的部分并保留中间数 e.g {1,4,5}, {2, 3, 7}
                bR = b;         //舍弃 B 中间点之后的部分并保留中间数
            }
            else{       //满足条件3
                aL = a+1;       //舍弃 A 中间点之前的部分和中间数
                bR = b;         //舍弃 B 中间点之后的部分并保留中间数
            }      
        }
        else{                           
            if ((aL + aR) % 2 == 0){     //如果个数为奇数
                aR = a;         //舍弃 A 中间点之前的部分并保留中间数 e.g {1,4,5}, {2, 3, 7}
                bL = b;         //舍弃 B 中间点之后的部分并保留中间数
            }
            else{
                aR = a;         //舍弃 A 中间点之后的部分并保留中间数
                bL = b+1;       //舍弃 B 中间点之前的部分和中间数
            }
        }
        
    }
    return A[a] < B[b] ? A[a] : B[b];
}
/* 时间复杂度为(log2n) 空间复杂度为O(1)*/


/* 12. 找到一个长度为n的整数序列A的主元素(即为数量最多的那个数,且数量m > n/2),
        若存在则输出,否则输出-1 */
/* 
    设计思想:从前向后扫描数组元素
    1. 选取候选的主元素
        依次扫描数组的每个数,将第一个遇到的数num保存到c中,记录num出现的次数为1;若遇到的下个数
    仍是num,则计数+1,否则-1;当计数为0时,将遇到的下一个数保存在c中,重新计数为1,重复上述步骤。
    2. 判断c是否为真正的主元素
        再次扫描数组,统计c中元素出现的次数,若 > n/2,则为主元素,否则不是。 
 */
int Majority(int A[], int n){
    int c, count = 1;
    c = A[0];
    for (int i = 1; i < n; i++)
        if (A[i] == c)
            count++;
        else
            if (count > 0)
                count--;
            else{       //更换主元,重新计数
                c = A[i];
                count = 1;
            }
    if (count > 0)
        for(int i = 0; i < n; i++)      //统计主元出现的实际次数
            if (A[i] == c)
                count++;
    return count > n/2 ? c : -1;    
}
/* 时间复杂度O(n), 空间复杂度O(1) */

/* 13. 找到 n 个整数的数组A中未出现的最小正整数 */
/* 
    设计思想:用一个数组B[n]来标记数组A中是否出现了1~n的整数,B[0] = 1;
 */
void findMissMin(int A[], int n){
    int *B;     //标记数组B
    B = (int *)malloc(sizeof(int) * n);
    memset(B, 0, sizeof(B));        //将数组B赋初值为0
    for (int i = 0; i < n; i++)
        if (A[i] > 0 && A[i] <= n)     //若A[i]的值在 1~n 之间,则标记数组B
            B[A[i]-1] = 1;
    for (int i = 0; i < n; i++)     //扫描数组B,返回目标值
        if (B[i] == 0)
            return i+1;
}
/* 时间复杂度为O(n), 空间复杂度为(n) */


int main(){
    SqList L;
    SeqList S;
    //C的动态分配
    L.data = (ElemType*) malloc (sizeof(ElemType) * InitSize);

    //C++的动态分配
    S.data = new ElemType[InitSize];

    return 0;
}
原文地址:https://www.cnblogs.com/astonc/p/13449319.html