线性表的顺序表示

线性表

可以理解成数组形式

一、线性表的定义

#include<bits/stdc++.h>
using namespace std;
#define Maxsize 50
#define InitSize 10
初始化定义线性表
typedef struct 
{
    int *data;
    int  MaxSize,length;
} SqList;

我们采用动态分配数组指针,Maxsize则为线性表的最大容量,length则为
线性表的当前个数

把线性表的初始操作定义一下:
InitList(&L): 初始化线性表
GetElem(L,i):按位查找
LocateElem(L,e):按照值查找

void InitList(SqList &L)
{
    L.data = new int[InitSize];
    L.length=0;
    L.MaxSize=InitSize;
}
void IncreaseSize(SqList &L, int len)
{
    int *p=L.data;
    int sum =L.MaxSize+len;
    L.data=new int[sum];
    for(int i=0; i<L.length;i++)
    {
        L.data[i]=p[i];
    }
    L.MaxSize = L.MaxSize+len;
    free(p);
}

int GetInt(SqList L, int i){
    return L.data[i];
}

int LocateElem(SqList L, int e){
    for(int i=0;i<L.length;i++){
        if(L.data[i] == e)
           return i+1;
    }
    return 0;
}

注:我们也可以用C语言的动态分配

L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);

二、顺序表的插入和删除操作

插入
在第i个位置插入,所以顺序表的位置实则为i-1;
从L.length到递减,使得数据后移所以data[j] = data[j-1];
注意:j是从L.length开始,在最开始就把该元素加上(相当于)

bool ListInsert(SqList &L,int i, int 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;
}

删除

删除则为把元素前移,即为data[j-1]=data[j];
从i开始,因为i-1即为被删数据的原来的位置。

bool ListDelete(SqList &L,int i,int &e)
{
    if(i<1||i>L.length+1)
        return false;
    e = L.data[i-1];
    for(int j=i;j<L.length;j++)
        L.data[j-1]=L.data[j];
    L.length--;
    return true;
}

三、线性表做题思想、思路!!!!!

1.将线性表逆置,空间复杂度为O(1)

最简单的思想就是求出一半位置,然后用总长度减去当前位置得到第二个数据位置,然后互换位置,因为用单个temp变量即可实现,所以复杂度为O(1);

void reverse(SqList &L)
{
    int item;
    for(int i=0;i<L.length/2;i++)
    {
        item = L.data[i];
        L.data[i] = L.data[L.length-1-i];
        L.data[L.length-1-i] = item;
    }
}

2.删除顺序表中等于X的数据

主要思想:重新定义数组中的值,即把不等于X的值用K来计数,把k++即可。

void Delete_X(SqList &L, int x)
{
    int k;
    for(int i=0;i<L.length;i++)
    {
        if(L.data[i] != x)
        {
            L.data[k] = L.data[i];
            k++;
        }
    }
    L.length=k;
}

3.删除顺序表其值在s和t之间的数据(不是有序顺序表)

我们可以计数,即把在s和t之间的数据计数用一个k变量,然后遇到不是在s和t之间的数据我们就将其移动k个位置即可!!!!

bool Delete_Between(SqList &L, int s, int t)
{
    if(s>=t)
       return 0;
    else if(L.length == 0)
       return 0;
    else
    {
        int k=0;
        for(int i=0;i<L.length;i++)
        {
            if(L.data[i]>=s && L.data[i] <=t)
            {
                k++;
            }
            else
            {
                L.data[i-k] = L.data[i];
            }
        }
        L.length -= k;
        return true;
    }
}

4.删除有序顺序表中的重复元素

有序顺序表中相同元素都是连续的,所以我们可以通过判断值的不同然后移动指针,指针只有在不同元素的时候才会移动。

bool Delete_Same(SqList &L)
{
    if(L.length == 0)
       return false;
    int i=0,j=1;
    for(;j<L.length;j++)
    {
        if(L.data[i] != L.data[j])
        {
            L.data[++i] = L.data[j];
        }
    }
    L.length = i+1;
    return true;
}

5.一个线性表中由两个线性表构成,将两个线性表的位置互换。

我们可以通过整体逆置的做法,将整个顺序表逆置,然后分别对于两个线性表采用逆置方法

void Reverse(SqList &L, int from, int to) {
  int i,temp;
  for(i=0;i<(to-from+1)/2;i++)
  {
      temp=L.data[from+i];
      L.data[from+i]=L.data[to-i];
      L.data[to-i]=temp;
  }
}
void Converse(SqList &L, int n, int p)
{
   Reverse(L.data,0,p-1);
   Reverse(L.data,p,n-1);
   Reverse(L.data,0,n-1);
}

6.中位数问题,两个升序等长顺序表,找出两个顺序表共同的中位数

我们可以理解为折半查找,我们可以现通过n/2先判断两个顺序表的中位数,倘若相同直接输出即可。再者如果比较较小的一方,倘若顺序表的总长为偶数的话,则将中位数和小于它的数一并排除,若为奇数将小于中位数的数排除。大于的一方删除比中位数大的数,奇数偶数判断与上述相同。

int M_search(SqList &L1, SqList &L2, int n){
    int s1=0,d1=n-1,m1,s2=0,d2=n-1,m2;
    while(s1!=d1||s2!=d2){
        m1=(s1+d1)/2;
        m2=(s2+d2)/2;
        if(L1.data[m1]==L2.data[m2]){
            return L1.data[m1];
        }
        if(L1.data[m1]<L2.data[m2]){
            if((s1+d1)%2==0){ //判断是否为偶数,一开始加和为奇数
                s1=m1;  //奇数保持的原则为排除中位数以后或者之前的元素
                d2=m2;
            }
            else{   //偶数判断原则为向前移动的顺序表排除中位数及其前面的数,往后移动的则为排除中位数以后的数
                s1=m1+1;
                d2=m2;
            }
        }
        else{
            if((s1+d1)%2==0){
                d1=m1;
                s2=m2;
            }
            else{
                d1=m1;
                s2=m2+1;
            }
        }
    }
    return L1.data[s1]<L2.data[s2]?L1.data[s1]:L2.data[s2];
}

总结:在判断奇数偶数后,奇数则移动到中位数位置即可,偶数的话向前移动的要移动到中位数后,不包括中位数,往后移动的移动到中位数位置即可。

7.找出顺序表中的主元素,主元素为大于总元素的一半即为主元素,没有则输出-1;

我们采用给元素记数的方式,即遇到该元素我们可以将其记录下来,将其值加一,如果遇到不是该值的数,则将其记录数减一,如果小于0了,则我们可以换数,即向前推进数组。因为主元素是大于一半的数量,所以我们能到它的计数一定能大于0,所以遍历完数组后,记录的数即为主元素。

int Majority(SqList &L, int n)
{
    int i,count=1;
    int flag=L.data[0];

    for(i=1;i<L.length;i++)
    {
        if(L.data[i]!=flag)
        {
            count--;
            if(count == 0)
               flag = L.data[i];
            count = 1;
        }
        else
        {
            count++;
        }
    }
    if(count>0)
    {
        for(i=count=0;i<n;i++)
        {
            if(L.data[i]==flag)
            {
                count++;
            }
        }
    }
    if(count>n/2) return flag;
    else return -1;
}

8.找出顺序表中最小正整数

通过增加空间复杂度来实现算法。我们要找到最小正整数,我们可以调用额外的数组,将小于零的数排除,然后设置一个长度为n的数组,然后置0,对于大于零的数计数,即相应位置计数,即存在,则在数组相应位置进行计数。通过循环,找到第一个为0的位置,则找到了顺序表中最小的正整数。

int findMissmin(SqList &L, int n)
{
    int i, *B;
    B = (int *)malloc(sizeof(int)*n);
    // B = new int[n];
    memset(B,0,sizeof(int)*n);
    for(i=0;i<L.length;i++)
    {
        if(L.data[i]>0&&L.data[i]<=n)
        {
            B[L.data[i]-1]=1;
        }
    }
    for(i=0;i<n;i++)
    {
        if(B[i] == 0)
        {
            break;
        }
    }
    return i+1;
}

注意我们的n就是想要求得数组长度,因为里面得数再大我们要找得是最小正整数,所以我们要考虑的是在n范围之内的。

9.

简单描述一下为三个数之间的距离和最小,三个数分别从不同的数组中取出。首先,三个数相等是最小的情况。再者我们可以通过画出图形的方式求解。
在这里插入图片描述

所以将问题转化成求解|c-a|最小即可,每次固定c去找a。最小值为a,最大值为c,通过c变,更新a得到最小距离。

bool three_min(int a, int b, int c)
{
    if (min(a, b, c) == a) return true;
    return false; 
}

int findMinofTrip(SqList &L1, int n, SqList &L2, int m, SqList &L3, int p)
{
    int i=0,j=0,k=0, D_min=INT_MAX,D;
    while (i<n && j<m && k<p && D_min>0)
    {
        D=abs(L1.data[i]-L2.data[j])+
        abs(L2.data[j]-L3.data[p])+
        abs(L1.data[i]-L3.data[p]);
        if(D<D_min)
            D_min = D;
        if(three_min(L1.data[i], L2.data[j], L3.data[p])) i++;
        else if(three_min(L2.data[i], L1.data[j], L3.data[p])) 
        j++;
        else p++;   
    }
    return D_min;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值