线性表由存储结构的不同可以分为顺序表和链表。
- 顺序表
对于顺序表,首先就是熟悉类型定义,一定要熟悉增删改查的基本操作。
类型定义
#define LIST_INIT_SIZE 100
#define LISTINCREMENT_SIZE 10
typedef struct{
ElemType*data;
int length;//当前长度
int maxsize;//当前分配的存储容量
}Sqlist;
动态分配语句为
L.elem=(ElemType*)malloc(sizeof(Elemtype)*LISTINCREMENT);
- 增加操作
增加操作在各大考研习题中考察不多,代码也不难,出题方向主要是在代码细节,但代码中的基本原理需要掌握。
bool SqListInsert(SqList &L,int i,ElemType e)//在顺序表中第i个位置插入新元素e
{
if(i<1||i>L.length+1)
return false;
if(L.length>=MaxSize)
return false;
for(int j=L.length-1;j>=i-1;j--)//将第i个元素后的元素推后一位
L.data[j+1]=L.data[j];
L.data[i]=e;//插入元素e
L.length++;//更新length值
return ture;
}
注意细节:位序和数组下标的区别
时间复杂度分析:
最好情况,后移语句不执行,直接在表尾插入,元素后移;O(1)
最坏情况,后移语句执行了n次,O(n)
平均情况,Pi=1/(n+1), 1/(n+1)*(0+1+2+3+4+…+n)=n/2, O(n)
3.删除操作
删除操作在考察过程中通常不会给定位置要求删除,所以我们需要利用查找算法找到要求被删除的元素的位置,然后进行删除操作,查找常常与高效的二分查找算法相结合,删除为固定代码。
bool SqListDelete(SqList &L, int i, ElemType x)//删除顺序表L中第i个位置的元素,若成功则返回true,并将被删除的元素用引用元素e返回,否则返回false。
{
if(i<1||i>length)
return false;
e=L.Data[i-1];//注意数组下标
for(int j=i;j<=length-1;j++)
L.Data[i-1]=L.Data[i];
L.length--;
return true;
}
//在一个顺序表中删除为x的元素,需要注意移动后续元素
void delete(SqList &L.ElemType x)
{
int k=0//记录不为x的元素下标7
for(int i=0;i<L.length;i++)
{
if(L[i]!=x)
{
L[k++]=L[i]
}
}
}
//删除重复的,我们运用一个工作指针
void delete_same(SqList &L)
{
int i=0,j=1;
for(i,j;i<L.length;j++)
{
if(L[i]!=L[j])
L[++i]=L[j];
}
L.length=i+1;
return true;
}
标志性语句:有序顺序表,最少时间查找。
思想:经典二分查找算法
bool binarysearch(SqList&L,ElemType x)//有序顺序表,最少时间查找,查到与后继交换,查不到则插入
{
int l=0,r=L.length-1;
while(l<=r)
{
mid=(l+r)/2;
if(L.data[mid]==x)
ElemType temp=L.data[mid];
L.data[mid]=L.data[mid+1];
L.data[mid+1]=ElemType temp;//c语言中的逆置算法,需掌握
return true.
else if(L.data[mid]<x)
l=mid+1;
else r=mid-1;
}
for(int j=L.length-1;j>=l;j--)
L.data[j+1]=L.data[j];
L.data[r]=x;//此处在何处插入x需要对于二分查找原理有了解
return true;
}
标志性语句:逆置算法,互换,左移
思想:明白逆置算法的原理,再对于基本需求进行逆置的组合。
void Reverse(DataType A[],int left,int right,int arraysize)//需掌握数组中逆置算法代码,多书写几遍
{
if(left>=right||rigth>=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]=temo;
}//需掌握数组中逆置算法代码
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);//多体会一下如何通过多次逆置交换能够交换前后两部分a1..am b1..bn
}
void left_transfer(DataType A[],int p)
{
reverse(A,0,n-1,arraysize);
reverse(A,n-1-p,n-1,arraysize);
reverse(A,0,n-2-p,arraysize);//逆置算法可以多种方法,结果一样即可
}
}
**标志性语句:**合并,两个有序顺序表,二路归并
bool Merge(SqList &A,SqList &B,SqList &C)//将两个有序的顺序表合并成一个顺序表
{
if(A.length+B.length>C.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;
return true;
}
//找到两个序列的中位数,可以先合并,然后直接输出就行。
int midnumber(SqList A,SqList B)
{
SqList C[A.length+B.length+10];
Merge(A,B,C);
if(C.length%2==0)
return C.length/2;
else return C.length/2+1;
}
标志性语句:辅助数组,可以将某整数值录入数组,并后续统计数组
int findmissMin(int A[],int n)//找到最小整数
{
int i,*B;
B=(int*)malloc(sizeof(int)*n);//分配数组的语句
for(i=0;i<n;i++)
B[i]==0;//辅助数组记得初始化
for(i=0;i<n;i++)
{if(A[i]>0&&A[i]<n)//注意理解A[i]的取值可以大于n,为了代码的健壮性,一定要
B[A[i]]=1;
}
for(i=1;i<n;i++)
{
if(A[i]==0)
return i;
}
}
int major(int A[],int n)//找到大于n/2的相同的数
{
int*B;
B=(int*)malloc(sizeof(int)*n)
for(int i=0;i<n;i++)
B[i]=0;
for(int j=0;j<n;j++)
{
B[A[j]]++;
}
for(int k=0;k<n;k++)
{
if(B[k]>n/2)
return k;
}
return -1;
}