数据结构(四)——线性表的公式化描述小结

本文为公式化描述的抽象小记,不涉及基础知识。

公式化线性表的核心操作:插入、删除、合并和搜索
公式化线性表的操作 == 对数组的操作
解题时可能用到的技巧:元素逆置、二分搜索int类型模拟指针一点点想象力
时间空间复杂度要求:大部分情况:时间复杂度O(n),空间复杂度为O(1)。时间复杂度为O(logn)的题目较少,且最优解需要耗费时间。除非想不出其它解法,不轻易使用时间复杂度为O(nlogn)、O(n^2)解法,以及空间复杂度为O(n)的解法(比如创建大小为n的数组)。

练习(仅供参考,部分题目非最优解)


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

ElemType deleteMin(SqList &L)
{
    if(L.length == 0)
        throw "SqList is empty!";

    int index = 0;
    for(int i = 1; i < L.length; i++)
    {
        if(L.data[i] < L.data[index])
            index = i;
    }
    ElemType res = data[index];
    data[index] = data[L.length-1];
    L.length--;

    return res;
}

//设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为大O(1)

void reverses(SqList &L)
{
    if(L.length < 2)
        return;
    ElemType temp;
    for(int i = 0; i < (L.length/2); i++)
    {
        temp = data[i];
        data[i] = data[L.length - 1 - i];
        data[L.length - 1 -i] = temp;
    }
}
// 对长度为n的顺序表L, 编写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法
// 删除线性表中所有值为x的数据元素
void deleteAllx(SqList &L, const ElemType &x)
{
    int k = 0;
    int temp = 0;
    for(int i = 0; i < L.length; i++)
        if(L.data[i] == x)
            k++;

    for(int i = 0;i < L.length; i++)
        if(data[i] != x)
            data[temp++] = data[i];

    L.length = L.length - k;

}

//从有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,如果是s或t不合理或顺序表
//为空,则显示出错信息并退出运行
void deleteSt(SqList &L, const ElemType &s, const ElemType &t)
{
    if(s >= t || L.length < 1)
        throw "s should be smaller than t";

    int k = 0;
    int temp = 0;
    for(int i = 0; i < L.length; i++)
        if(L.data[i] >=s || L.data[i] <= t)
            k++;

    for(int i = 0;i < L.length; i++)
        if(L.data[i] < s || L.data[i] > t)
            data[temp++] = data[i];

    L.length = L.length - k;
}
//从有序顺序表中删除所有其值重复的元素,使表中的元素各不相同
void deleteRepeatSortedSqList(SqList &L)
{
    if(L.length < 2)
        return ;

    int temp = 1
    for(int i = 1; i < L.length; i++)
    {
        if(L.data[i] != data[i-1])
            data[temp++] = data[i];
    }
    L.length = temp;
}
//将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表
void mergeSortedSqList(const SqList &L1, const SqList &L2, SqList &Res)
{

    int s = 0;
    int t = 0;
    int q = 0;
    while(s < L1.length && t < L2.length)
    {
        if(L1.data[s] <= L2.data[t])
            Res.data[q++] = L1.data[s++];
        else
            Res.data[q++] = L1.data[t++];
    }


    if(s < L1.length)
    {
        for(int i = s; i < L1.length; i++)
        {
            Res.data[q++] = L1.data[s++];
        }
    }else
    {
        for(int i = t; i < L2.length; i++)
        {
            Res.data[q++] = L1.data[t++];
        }
    }

}
//已知在一维数组A[m+n]中依次存放两个线性表(a1,a2,a3,a4,..,am)和(b1,b2,b3,...,bn).
//试编写一个函数,将数组中两个顺序表的位置互换,即将(b1,b2,b3,...,bn)放在
void reversesSq(SqList &L,int m, int n)
{
    if(L.length < 2)
        return;
    ElemType temp;
    for(int i =0; i < ((n - m+1)/2); i++)
    {
        temp = L.data[i+m-1];
        L.data[i+m-1] = L.data[n-1-i];
        L.data[n-1-i] = temp;
    }
}

void swapArray(SqList &L,int m, int n)
{
    reverses(L);
    reversesSq(L, 0, m);
    reversesSq(L, m+1,m+n);
}

//线性表(a1, a2,a3, ...,an)中的元素递增有序且按顺序存储于计算机内。要求设计一算法,完成
//用最少的时间在表中查找数值为x的元素,若找到则将其与后继元素位置互换,若找不到则将其插
//入表中并使表中元素扔递增有序。
void Binary(SqList &L,const ElemType x)
{
    int p1 = 0;
    int p2 = L.length;
    int p = (p1+p2)/2;

    ElemType temp;
    while(p2 >= p1)//查找并替换
    {
        if(L.data[p] == x && p != L.length - 1)
        {
            temp = data[p];
            L.data[p] = L.data[p+1];
            L.data[p+1] = L.data[p];
            return;

        }else if(L.data[p] < x)
        {
            p1 = p+1;
            p = (p1+p2)/2;

        }else if(L.data[p] > x)
        {
            p2 = p-1;
            p = (p1+p2)/2;
        }
    }
    //找不到便插入,此时p1>p2,插入p1处,即使在边界处也一样
    for(int i = L.length; i>=p1;i--)
    {
        L.data[i+1] = L.data[i];
    }
    L.data[i+1] = x;
}
//设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面
//都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将
//R中的数据由(X0,X1,..,Xn-1)变换为(Xp,Xp+1,..,Xn-1,X0,X1,...,Xp-1)
//需要一点想象力
/*
    设计思想:将数组分为两个数组ab,变换后应为ba。
    首先我们分别翻转ab,使之成为(a-1)(b-1)
    再对整个数组进行翻转((a-1)(b-1))-1
    结果为ba
*/

void cycleLeft(SqList &L, int m)
{
    reversesSq(L, 0, m);
    reversesSq(L, m+1, L.length);
    reverses(L);
}

/*

    空间复杂度:大O(1)
    时间复杂度:大O(n)
*/

//一个长度为L的升序序列S,处在[L/2](向上取整)个位置的数称为S的中位数。
//两个等长序列的中位数是含它们所有元素的升序序列的中位数。试设计一个在时间
//和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数
/*
    算法思想:
    找第[L/2](向上取整)大的数
    因为是升序序列,只需按数组合并算法比对就可
    序列等长
*/

ElemType findMedian(const SqList &L1,const SqList &L2)
{
    int p = 0;
    int m = 0;
    int n = 0;
    ElemType res;
    while(p < L1.length)
    {
        if(L1.data[m] >= L2.data[n])
            res = data[m++];
        else
            res = data[n++];
        p++;
    }
    return res;
}
/*
    空间复杂度:大O(1)
    时间复杂度:大O(n),非最优解,最优解为大O(logn)
    最优解思想:循环比较两个两个数组的中位数,舍弃边缘元素(即中位数数一边不可能为两数组中位数的元素),最后会得到两个数组的中位数相同或只剩两个元素,若只剩两个元素,取小的那个。
    缺点:不通用,不可以用于求不等长两数组的中位数;逻辑繁琐。
*/
//寻找主元素,即出现次数大于n/2的元素
/*
首先利用名次排序,空间复杂度O(n),时间复杂度为O(n),非最优解,最优解空间复杂度为O(1)
最优解思想:取一个int类型值依次记录数组元素的出现次数,相同加一,不同减一,减为0替换候选元素,出现次数
重置为一。利用了题目中主元素出现次数大于n/2的性质,不适用求出现次数最多的元素。
*/

int findMajor(const SqList &L, int n)
{
    int array[n];
     int res = 0;
     int p;
    for(int i = 0;i<n;i++)
        array[i] = 0;
    for(int i = 0; i<L.length;i++)
        array[L.data[i]]++;

    for(int i = 0;i<n;i++)
    {
        if(res < array[i])
        {
            res = array[i];
            p = i;
        }

    }
    if(res <= n/2)
        return -1;
    else
        return p;
}

/*
找出未出现的最小正整数,小于1的数直接忽略,
要求时间上高效,直接建立大小为n数组
*/
int findMinP(const int a[])
{
    int n = sizeof(a)/sizeof(arr[0]);
    memset[b, 0, n*sizeof(int)];

    for(int i =0;i < n;i++)
        if(a[i]>0)
            b[a[i]]++;
    for(int i = 0; i < n; i++)
    {
        if(b[i] == 0)
            return i;
    }
}
//时间复杂度O(n)
//空间复杂度O(n)




猜你喜欢

转载自blog.csdn.net/qq_41882686/article/details/106693119