线性表
可以理解成数组形式
一、线性表的定义
#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.![](https://i-blog.csdnimg.cn/blog_migrate/aeb6784fcbd3a9776e3ff281e5b79dde.jpeg#pic_center)
简单描述一下为三个数之间的距离和最小,三个数分别从不同的数组中取出。首先,三个数相等是最小的情况。再者我们可以通过画出图形的方式求解。
所以将问题转化成求解|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;
}