一、线性表及其逻辑结构
(一)定义
线性表是一个具有相同特性的数据元素的有限序列。
线性表的逻辑表示为
( a1,a2,…,ai,ai+1,…,an )
ai(1≤i≤n)表示第i(i表示逻辑位序)个元素,a1为表头元素,an为表尾元素。
(二)基本运算
初始化线性表InitList(&L):构造一个空的线性表L。
销毁线性表DestroyList(&L):释放线性表L占用的内存空间。
判线性表是否为空表ListEmpty(L):若L为空表,则返回真,否则返回假。
求线性表的长度ListLength(L):返回L中元素个数n。
输出线性表DispList(L):线性表L不为空时,顺序显示L中各结点的值域。
求线性表L中指定位置的某个数据元素GetElem(L,i,&e):用e返回L中第i(1≤i≤n)个元素的值。
定位查找LocateElem(L,e):返回L中第一个值域与e相等的逻辑位序。若这样的元素不存在,则返回值为0。
插入一个数据元素ListInsert(&L,i,e):在L的第i(1≤i≤n)个元素之前插入新的元素e,L的长度增1。
删除数据元素ListDelete(&L,i,&e):删除L的第i(1≤i≤n)个元素,并用e返回其值,L的长度减1。
二、线性表的顺序存储结构
(一)顺序表的存储和声明
声明线性表的顺序存储类型时,采用结构体类型SqList表示如下
#define MaxSize 50
typedef int ElemType;
typedef struct{
ElemType data[MaxSize];
int length;
} SqList;
(二)部分运算实现
1.建立顺序表
void CreateList(SqList *&L,ElemType a[],int n){
int i=0,k=0;
L=(SqList *)malloc(sizeof(SqList)); //分配存放线性表的空间
while(i<n){
L->data[k]=a[i];
k++;
i++;
}
L->length=k;
}
2.初始化线性表
void InitList(SqList *&L){
L=(SqList *)malloc(sizeof(SqList)); //分配存放线性表的空间
L->length=0;
}
3.插入数据元素
bool ListInsert(SqList *&L,int i,ElemType e){
int j;
if(i<1||i>L->length+1)
return false;
i--; //将逻辑序号转化为物理序号
for(j=L->length;j>i;j--) //将data[i]及后面元素后移一个位置
L->data[j]=L->data[j-1];
L->data[i]=e;
L->length++;
return true;
}
4.删除数据元素
bool ListDelete(SqList *&L,int i,ElemType &e){
int j;
if(i<1||i>L->length)
return false;
i--; //将逻辑序号转化为物理序号
e=L->data[i];
for(int j=i;j<L->length-1;j++) //将data[i]及后面元素前移一个位置
L->data[j]=L->data[j+1];
L->length--;
return true;
}
三、线性表的链式存储结构
(一)单链表
1.单链表的存储和声明
在单链表中,每个结点类型用LinkNode表示如下
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
} LinkNode;
2.建立单链表
(1)头插法
void CreateListF(LinkNode *&L,ElemType a[],int n){
LinkNode *s;
L=(LinkNode*)malloc(sizeof(LinkNode));
L->next=NULL;
for(int i=0;i<n;i++){
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i];
s->next=L->next;
L->next=s;
}
}
(2)尾插法
void CreateListR(LinkNode *&L,ElemType a[],int n){
LinkNode *s,*r;
L=(LinkNode *)malloc(sizeof(LinkNode));
r=L;
for(int i=0;i<n;i++){
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i];
r->next=s;
r=s;
}
r->next=NULL;
}
3.部分基本运算的实现
(1)初始化线性表
void InitList(LinkNode *&L){
L=(LinkNode *)malloc(sizeof(LinkNode));
L->next=NULL;
}
(2)销毁线性表:需要逐一释放全部结点的空间
void DestroyList(ListNode *&L){
LinkNode *pre=L,*p=L->next; //pre指向p的前驱结点
while(p!=NULL){
free(pre);
pre=p;
p=pre->next; //pre、p同步后移一个结点
}
free(pre);
}
(3)插入数据元素
bool ListInsert(LinkNode *&L,int i,ElemType e){
int j=0;
LinkNode *p=L,*s;
if(i<=0)
return false;
while(j<i-1&&p!=NULL){
j++;
p=p->next;
}
if(p==NULL)
return false;
else{
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
}
(4)删除数据元素
bool ListDelete(LinkNode *&L,int i,ElemType &e){
int j=0;
LinkNode *p=L,*q;
if(i<=0)
return false;
while(j<i-1&&p!=NULL){
j++;
p=p->next;
}
if(p==NULL)
return false;
else{
q=p->next;
if(q==NULL)
return false;
e=q->data;
p->next=q->next;
free(q);
return true;
}
}
(二)双链表
1.双链表的存储和声明
对于双链表,其结点类型DLinkNode的声明如下:
typedef struct DNode{
ElemType data;
struct DNode *prior;
struct DNode *next;
} DLinkNode;
2.建立双链表
(1)头插法
void CreateListF(DLinkNode *&L,ElemType a[],int n){
DLinkNode *s;
L=(DLinkNode *)malloc(sizeof(DLinkNode));
L->prior=L->next=NULL;
for(int i=0;i<n;i++){
s=(DLinkNode *)malloc(sizeof(DLinkNode));
s->data=a[i];
s->next=L->next;
if(L->next!=NULL)
L->next->prior=s;
L->next=s;
s->prior=L;
}
}
(2)尾插法
void CreateListR(DLinkNode *&L,ElemType a[],int n){
DLinkNode *s,*r;
L=(DLinkNode *)malloc(sizeof(DLinkNode));
r=L;
for(int i=0;i<n;i++){
s=(DLinkNode *)malloc(sizeof(DLinkNode));
s->data=a[i];
r->next=s;
s->prior=r;
r=s;
}
r->next=NULL;
}
3.部分基本运算的实现
(1)插入数据元素
bool ListInsert(DLinkNode *&L,int i,ElemType e){
int j=0;
DLinkNode *p=L,*s;
if(i<=0)
return false;
while(j<i-1&&p!=NULL){
j++;
p=p->next;
}
if(p==NULL)
return false;
else{
s=(DLinkNode *)malloc(sizeof(DLinkNode));
s->data=e;
s->next=p->next;
if(p->next!=NULL)
p->next->prior=s;
s->prior=p;
p->next=s;
return true;
}
}
(2)删除数据元素
bool ListDelete(DLinkNode *&L,int i,ElemType &e){
int j=0;
DLinkNode *p=L,*q;
if(i<=0)
return false;
while(j<i-1&&p!=NULL){
j++;
p=p->next;
}
if(p==NULL)
return false;
else{
q=p->next;
if(q==NULL)
return false;
e=q->data;
p->next=q->next;
if(p->next!=NULL)
p->next->prior=p;
free(q);
return true;
}
}
(三)循环链表
循环单链表:将表中尾结点的指针域改为指向表头结点,整个链表形成一个环。由此从表中任一结点出发均可找到链表中其他结点。
循环双链表:将尾结点的next指针域由原来为空指向头节点,将它的头结点的prior指针域改为指向尾结点,整个双链表形成两个环。
四、线性表相关应用
26.删除有序数组中的重复项【双指针】
给你一个 升序排列 的数组
nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回nums
中唯一元素的个数。考虑
nums
的唯一元素的数量为k
,你需要做以下事情确保你的题解可以被通过:
- 更改数组
nums
,使nums
的前k
个元素包含唯一元素,并按照它们最初在nums
中出现的顺序排列。nums
的其余元素与nums
的大小不重要。- 返回
k
。
4.寻找两个正序数组的中位数【二分查找】
给定两个大小分别为
m
和n
的正序(从小到大)数组nums1
和nums2
。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为
O(log (m+n))
。
给你单链表的头指针
head
和两个整数left
和right
,其中left <= right
。请你反转从位置left
到位置right
的链表节点,返回 反转后的链表 。
给你链表的头节点
head
,每k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k
的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。