1.顺序表
1.1 顺序表的定义
1.1.1 静态分配:
#include<stdio.h>
#define MaxSize 10
typedef struct{
int data[MaxSize];
int length;
}Sqlist;
//初始化一个顺序表
void InitList(Sqlist &L){
for(int i=0;i<MaxSize;i++){
//TODO
L.data[i]=0;//将所有数据元素设置为默认初始值
}
L.length=0;//顺序表初始长度为0
}
int main()
{
Sqlist L;//声明一个顺序表
InitList(L);
for(int i=0;i<MaxSize;i++)
{
printf("data[%d]:%d\n",i,L.data[i]);
}
return 0;
}
如果不将所有数据元素设置为默认初始值的话,数组元素中就会有各种奇奇怪怪的数据,这是因为内存中会有遗留的“脏数据”
1.1.2 动态分配:
#include<stdio.h>
#include<stdlib.h>
#define InitSize 10//默认的最大长度
typedef struct{
int *data;//指示动态分配数组的指针
int MaxSize;//顺序表的最大容量
int length;//顺序表的当前长度
}Seqlist;
void InitList(Seqlist &L)
{
//用malloc函数申请一片连续的存储空间
L.data=(int *)malloc(InitSize*sizeof(int));
L.length=0;
L.MaxSize=InitSize;
}
//增加动态数组的长度
void IncreaseSize(Seqlist &L,int len){
int *p=L.data;
L.data=(int *)malloc((L.MaxSize+len)*sizeof(int));
for(int i=0;i<L.length;i++)
{
L.data[i]=p[i];
}
L.MaxSize=L.MaxSize+len;
free(p);
}
int main()
{
Seqlist L;//声明一个顺序表
InitList(L);//初始化顺序表
IncreaseSize(L,5);
return 0;
}
1.2 顺序表上的基本操作
1.2.1 插入操作
#include<stdio.h>
#define MaxSize 10
typedef struct{
int data[MaxSize];
int length;
}Sqlist;
//初始化一个顺序表
void InitList(Sqlist &L){
for(int i=0;i<MaxSize;i++){
//TODO
L.data[i]=0;//将所有数据元素设置为默认初始值
}
L.length=0;//顺序表初始长度为0
}
bool ListInsert(Sqlist &L,int i,int e)
{
if(i<1||i>L.length+1) return false;//判断i的范围是否有效
if(L.length>=MaxSize) return false;//判断当前存储空间是否已满
for(int j=L.length;j>=i;j--)//将第i个元素及之后元素后移
{
L.data[j]=L.data[j-1];
}
L.data[i-1]=e;//在位置i处插入e
L.length++;//长度加一
return true;
}
int main()
{
Sqlist L;//声明一个顺序表
InitList(L);
L.data[0]=0,L.length++;
L.data[1]=1,L.length++;
L.data[2]=2,L.length++;
ListInsert(L,2,3);
for(int i=0;i<L.length;i++)
{
printf("data[%d]:%d\n",i,L.data[i]);
}
return 0;
}
1.2.2 删除操作
#include<stdio.h>
#define MaxSize 10
typedef struct{
int data[MaxSize];
int length;
}Sqlist;
//初始化一个顺序表
void InitList(Sqlist &L){
for(int i=0;i<MaxSize;i++){
//TODO
L.data[i]=0;//将所有数据元素设置为默认初始值
}
L.length=0;//顺序表初始长度为0
}
bool ListDelete(Sqlist &L,int i,int &e)
{
if(i<1||i>L.length+1) return false;//判断i的范围是否有效
e=L.data[i-1];
for(int j=i;j<L.length;j++)//将第i个元素之后的元素前移
{
L.data[j-1]=L.data[j];
}
L.length--;//长度减一
return true;
}
int main()
{
Sqlist L;//声明一个顺序表
InitList(L);
int e=-1;
L.data[0]=0,L.length++;
L.data[1]=1,L.length++;
L.data[2]=2,L.length++;
L.data[3]=3,L.length++;
if(ListDelete(L,3,e))
printf("被删除的元素为%d\n",e);
else
printf("位序i不合法,删除失败\n");
for(int i=0;i<L.length;i++)
{
printf("data[%d]:%d\n",i,L.data[i]);
}
return 0;
}
1.2.3 查找操作
按位查找
ElemType GetElem(SeqList L,int i)
{
return L.data[i-1];
}
按值查找
#include<stdio.h>
#include<stdlib.h>
#define InitSize 10//默认的最大长度
typedef struct{
int *data;//指示动态分配数组的指针
int MaxSize;//顺序表的最大容量
int length;//顺序表的当前长度
}Seqlist;
void InitList(Seqlist &L)
{
//用malloc函数申请一片连续的存储空间
L.data=(int *)malloc(InitSize*sizeof(int));
L.length=0;
L.MaxSize=InitSize;
}
//增加动态数组的长度
void IncreaseSize(Seqlist &L,int len){
int *p=L.data;
L.data=(int *)malloc((L.MaxSize+len)*sizeof(int));
for(int i=0;i<L.length;i++)
{
L.data[i]=p[i];
}
L.MaxSize=L.MaxSize+len;
free(p);
}
int LocateElem(Seqlist L,int e)
{
for(int i=0;i<L.length;i++)
{
if(L.data[i]==e)
return i+1;
}
return 0;
}
int main()
{
Seqlist L;//声明一个顺序表
InitList(L);//初始化顺序表
//IncreaseSize(L,5);
L.data[0]=1,L.length++;
L.data[1]=2,L.length++;
L.data[2]=3,L.length++;
// for(int i=0;i<L.length;i++){
// //TODO
// printf("L%d:%d\n",i,L.data[i]);
// }
printf("%d",LocateElem(L,2));
return 0;
}
2.链表
2.1单链表
2.1.1单链表的定义
struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
typedef struct LNode LNode;
typedef struct LNode *LinkList;//用LinkList表示这是一个指向LNode类型的指针
更简介的写法:
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
强调这是一个单链表 --使用LinkList
强调这是一个结点 --使用LNode *
不带头结点的单链表
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
bool InitList(LinkList &L)
{
L=NULL;
return true;
}
//bool Empty(LinkList L)
//{
// if(L==NULL) return true;
// else return false;
//}
bool empty(LinkList L)
{
return (L==NULL);
}
int main()
{
LinkList L;
InitList(L);
return 0;
}
带头结点的单链表
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{//定义单链表结点类型
int data;//每个结点存放一个数据元素
struct LNode *next;//指针指向下一个结点
}LNode,*LinkList;
bool InitList(LinkList &L)
{
L=(LNode *)malloc(sizeof(LNode));//分配一个头结点
if(L==NULL) return false;//内存不足,分配失败
L->next=NULL;//头结点之后暂时还没有结点
return true;
}
bool Empty(LinkList L)//判断单链表是否为空
{
if(L->next==NULL) return true;
else return false;
}
int main()
{
LinkList L;//声明一个指向单链表的指针
InitList(L);//初始化一个空表
return 0;
}
2.1.2单链表的插入
2.1.2.1按位序插入
在第i个位置插入元素e(带头结点)
typedef struct LNode
{
ELemType data;
struct LNode *next;
}LNode,*LinkList;
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<1) //位序肯定是大于等于1的
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //j用来表示当前p指向的是第几个结点
p=L; //刚开始先指向头结点,头结点是第0个结点(一般不存数据)
while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
{
p=p->next;
j++;
}
if(p==NULL) //i值不合法(如果插入的位置比总结点个数还大1的话)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next; //把p的后继结点变成s的后继结点
p->next=s; //p的后继结点变成s
return true;//插入成功
}
平均时间复杂度O(n)
不带头结点
typedef struct LNode
{
ELemType data;
struct LNode *next;
}LNode,*LinkList;
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<1) //位序肯定是大于等于1的
return false;
if(i==1) //插入第一个结点时与其他结点不同
{
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=L;
L=s; //把头指针指向新结点
return true;
}
LNode *p; //指针p指向当前扫描到的结点
int j=1; //j用来表示当前p指向的是第几个结点
p=L; //指向第1个结点(此时就不是头结点了)
while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
{
p=p->next;
j++;
}
if(p==NULL) //i值不合法(如果插入的位置比总结点个数还大一的话)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next; //把p的后继结点变成s的后继结点
p->next=s; //p的后继结点变成s
return true;//插入成功
}
2.1.2.2指定结点的后插操作
//后插操作,在p结点之后插入元素e
bool InsertNextNode(LNode *p,ElemType e)
{
if(p==NULL) return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL) //内存分配失败
return false;
s->data=e; //写入数据元素e
s->next=p->next;
p->next=s; //将s连到p之后
return true;
}
时间复杂度为O(1)
前面的插入函数就可以改成:
typedef struct LNode
{
ELemType data;
struct LNode *next;
}LNode,*LinkList;
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<1) //位序肯定是大于等于1的
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //j用来表示当前p指向的是第几个结点
p=L; //刚开始先指向头结点,头结点是第0个结点(一般不存数据)
while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
{
p=p->next;
j++;
}
return InsertNextNode(p,e);
}
2.1.2.3指定结点的前插操作
其实本质上还是后插操作,只是把原来前面结点的数据复制到后面的结点上,再把新的数据放到前面这个结点上,看起来就像前插操作。
bool InsertPriorLNode(LNode *p,ElemType e)
{
if(p==NULL) return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL) return false; //内存分配失败
s->next=p->next;
p->next=s; //新结点s放到p之后
s->data=p->data; //将p中元素复制到s中
p->data=e; //将新元素e放到p中,类似于前插操作
return true;
}
bool InsertPriorLNode(LNode *p,LNode *s)
{
if(p==NULL || s==NULL) return false;
s->next=p->next;
p->next=s;
ELemType temp=p->data; //设置一个临时变量存储p的数据
p->data=s->data;
s->data=temp;
return true;
}
2.1.3单链表的删除操作
2.1.3.1按位序删除
typedef struct LNode
{
ELemType data;
struct LNode *next;
}LNode,*LinkList;
bool ListDelete(LinkList &L,int i,ElemType &e)
{
if(i<1) //位序肯定是大于等于1的
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //j用来表示当前p指向的是第几个结点
p=L; //刚开始先指向头结点,头结点是第0个结点(一般不存数据)
while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
{
p=p->next;
j++;
}
if(p==NULL)
return false;
if(p->next==NULL) //第i-1个结点之后已经没有结点
return false;
LNode *q=p->next; //让q指向要被删除的结点
p->next=q->next; //将*q结点从链中断开
e=q->data; //用e返回元素的值
free(q); //释放结点的存储空间
return true;//删除成功
}
2.1.3.2删除指定结点
//删除指定结点p
bool DeleteNode(LNode *p)
{
if(p==NULL) return false;
LNode *q=p->next; //令q指向*p的后继结点
p->data=p->next->data; //和后继结点交换数据
p->next=q->next; //将*q从链中断开
free(q); //释放后继结点的存储空间
return true;
}
2.1.4单链表的查找
2.1.4.1按位查找
//按位查找,返回第i个元素(带头结点)
LNode *GetElem(LinkList L,int i)
{
if(i<0) return NULL;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //j表示当前p指向的是哪个结点
p=L; //L指向头结点,头结点是第0个结点
while(p!=NULL && j<i) //循环找到第i个结点
{
p=p->next;
j++;
}
return p;
}
LNode *GetElem(LinkList L,int i)
{
int j=1;//表示指针p刚开始在第一个结点
LNode *p=L->next;
if(i==0) return L;
if(i<1) return NULL;
while(p!=NULL && j<i)
{
p=p->next;
j++;
}
return p;
}
所以前面的插入还有删除函数都可以改成:
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<1) //位序肯定是大于等于1的
return false;
LNode *p=GetElem(L,i-1);
return InsertNextNode(p,e);
}
2.1.4.2按值查找
//按值查找,找到数据元素==e的结点
LNode *LocateElem(LinkList L,ElemType e)
{
LNode *p=L->next;
//从第一个结点开始查找数据为e的结点
while(p!=NULL && p->data!=e)
{
p=p->next;
}
return p;//找到后返回该结点指针,否则返回NULL
}
2.1.5求单链表的长度
int Length(LinkList L)
{
int len=0;//统计表长
LNode *p=L;
while(p->next!=NULL)
{
p=p->next;
len++;
}
return len;
}
2.1.6单链表的建立
2.1.6.1 尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
int x;
L=(LNode *)malloc(sizeof(LNode));
LNode *s;
LNode *r=L;
scanf("%d",&x);
while(x!=9999)
{
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
2.1.6.2 头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
LNode *s;
int x;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL; //初始为空链表
scanf("%d",&x); //输入结点的值
while(x!=9999)
{
s=(LNode*)malloc(sizeof(LNode));//创建新结点
s->data=x;
s->next=L->next;
L->next=s; //将新结点插入表中,L为头指针
scanf("%d",&x);
}
return L;
}
重要应用:链表的逆置
2.1.7 单链表实验程序
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
bool InitList(LinkList &L)
{
L=(LNode *)malloc(sizeof(LNode));
if(L==NULL) return false;
L->next=NULL;
return true;
}
bool Empty(LinkList L)
{
if(L->next==NULL) return true;
else return false;
}
//bool ListInsert(LinkList &L,int i,int e)
//{
// if(i<1) //位序肯定是大于等于1的
// return false;
// if(i==1) //插入第一个结点时与其他结点不同
// {
// LNode *s=(LNode *)malloc(sizeof(LNode));
// s->data=e;
// s->next=L;
// L=s; //把头指针指向新结点
// return true;
// }
// LNode *p; //指针p指向当前扫描到的结点
// int j=1; //j用来表示当前p指向的是第几个结点
// p=L; //指向第1个结点(此时就不是头结点了)
// while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
// {
// p=p->next;
// j++;
// }
// if(p==NULL) //i值不合法(如果插入的位置比总结点个数还大一的话)
// return false;
// LNode *s=(LNode *)malloc(sizeof(LNode));
// s->data=e;
// s->next=p->next; //把p的后继结点变成s的后继结点
// p->next=s; //p的后继结点变成s
// return true;//插入成功
//}
//后插操作,在p结点之后插入元素e
bool InsertNextNode(LNode *p,int e)
{
if(p==NULL) return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL) //内存分配失败
return false;
s->data=e; //写入数据元素e
s->next=p->next;
p->next=s; //将s连到p之后
return true;
}
//bool ListInsert(LinkList &L,int i,int e)
//{
// if(i<1) //位序肯定是大于等于1的
// return false;
// LNode *p; //指针p指向当前扫描到的结点
// int j=0; //j用来表示当前p指向的是第几个结点
// p=L; //刚开始先指向头结点,头结点是第0个结点(一般不存数据)
// while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
// {
// p=p->next;
// j++;
// }
// return InsertNextNode(p,e);
//}
//bool InsertPriorLNode(LNode *p,int e)
//{
// if(p==NULL) return false;
// LNode *s=(LNode *)malloc(sizeof(LNode));
// if(s==NULL) return false; //内存分配失败
// s->next=p->next;
// p->next=s; //新结点s放到p之后
// s->data=p->data; //将p中元素复制到s中
// p->data=e; //将新元素e放到p中,类似于前插操作
// return true;
//}
bool InsertPriorLNode(LNode *p,LNode *s)
{
if(p==NULL || s==NULL) return false;
s->next=p->next;
p->next=s;
int temp=p->data; //设置一个临时变量存储p的数据
p->data=s->data;
s->data=temp;
return true;
}
bool ListDelete(LinkList &L,int i,int &e)
{
if(i<1) //位序肯定是大于等于1的
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //j用来表示当前p指向的是第几个结点
p=L; //刚开始先指向头结点,头结点是第0个结点(一般不存数据)
while(p!=NULL && j<i-1) //用一个while循环找到第i-1个结点
{
p=p->next;
j++;
}
if(p==NULL)
return false;
if(p->next==NULL) //第i-1个结点之后已经没有结点
return false;
LNode *q=p->next; //让q指向要被删除的结点
p->next=q->next; //将*q结点从链中断开
e=q->data; //用e返回元素的值
free(q); //释放结点的存储空间
return true;//删除成功
}
//删除指定结点p
bool DeleteNode(LNode *p)
{
if(p==NULL) return false;
LNode *q=p->next; //令q指向*p的后继结点
p->data=p->next->data; //和后继结点交换数据
p->next=q->next; //将*q从链中断开
free(q); //释放后继结点的存储空间
return true;
}
//按位查找,返回第i个元素(带头结点)
LNode *GetElem(LinkList L,int i)
{
if(i<0) return NULL;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //j表示当前p指向的是哪个结点
p=L; //L指向头结点,头结点是第0个结点
while(p!=NULL && j<i) //循环找到第i个结点
{
p=p->next;
j++;
}
return p;
}
bool ListInsert(LinkList &L,int i,int e)
{
if(i<1) //位序肯定是大于等于1的
return false;
LNode *p=GetElem(L,i-1);
return InsertNextNode(p,e);
}
//按值查找,找到数据元素==e的结点
LNode *LocateElem(LinkList L,int e)
{
LNode *p=L->next;
//从第一个结点开始查找数据为e的结点
while(p!=NULL && p->data!=e)
{
p=p->next;
}
return p;//找到后返回该结点指针,否则返回NULL
}
int Length(LinkList L)
{
int len=0;//统计表长
LNode *p=L;
while(p->next!=NULL)
{
p=p->next;
len++;
}
return len;
}
int main()
{
LinkList L;
InitList(L);
ListInsert(L,1,1);
ListInsert(L,2,2);
ListInsert(L,3,3);
ListInsert(L,4,4);
LNode *a=GetElem(L,2);
printf("%d\n",a->data);
printf("%d\n",Length(L));
return 0;
}
2.2双链表
typedef struct DNode{ //定义双链表结点类型
Elemtype data; //数据域
struct DNode *prior, *next;//前驱和后继指针
}DNode,*DLinkList;
2.2.1 初始化双链表
bool InitDLinkList(DLinkList &L)
{
L=(DNode *)malloc(sizeof(DNode));
if(L==NULL) return false;
L->prior=NULL; //头结点的prior永远指向NULL
L->next=NULL; //头结点之后暂时还没有结点
return true;
}
//判断链表是否为空
bool Empty(DLinkList L)
{
if(L->next==NULL) return true;
else return false;
}
2.2.2 双链表的插入和删除
//在p结点之后插入s结点
bool InsertNextDNode(DNode *p,DNode *s)
{
if(p==NULL || s==NULL)
return false;
s->next=p->next;
if(p->next!=NULL) //如果p结点之后还有结点
p->next->prior=s;
s->prior=p;
p->next=s;
return true;
}
//删除p结点的后继结点
bool DeleteNextDNode(DNode *p)
{
if(p==NULL) return false;
DNode *q=p->next; //找到p的后继结点q
if(q==NULL) return false; //若p没有后继,返回false
p->next=q->next;
if(q->next!=NULL) //q结点不是最后一个结点
q->next->prior=p;
free(q); //释放结点空间
return true;
}
void Destory(DLinkList &L) //循环释放各个数据结点
{
while(L->next!=NULL)
DeleteNextDNode(L);
free(L); //释放头结点
L=NULL; //头结点指向NULL
}
2.2.3 双链表的遍历
//后向遍历
while(p->next!=NULL)
{
//todo
p=p->next;
}
//前向遍历
while(p->prior!=NULL)
{
//todo
p=p->prior;
}
2.3循环单链表
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
bool InitList(LinkList &L)
{
L=(LNode *)malloc(sizeof(LNode));
if(L==NULL) return false;
L->next=L; //头结点的next指向头结点
return true;
}
//判断循环单链表是否为空
bool Empty(LinkList L)
{
if(L->next==L) return true;
else return false;
}
//判断结点p是否为循环单链表的表尾结点
bool isTail(LinkList L,LNode *p)
{
if(p->next==L) return true;
else return false;
}
2.4 循环双链表
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
//初始化空的循环双链表
bool InitDlinkList(DLinkList &L)
{
L=(DLnode *)malloc(sizeof(DNode));
if(L==NULL)
return false;
L->prior=L; //头结点的prior指向头结点
L->next=L; //头结点的next指向头结点
return true;
}
//判断循环双链表是否为空
bool Empty(DLinkList L)
{
if(L->next==L)
return true;
else true false;
}
//判断结点p是否为循环双链表的的表尾结点
bool isTail(DLinkList L,DNode *p){
if(p->next==NULL) return true;
else return false;
}
int main()
{
DLinkList L;
InitDLinkList(L);
return 0;
}
//在p结点之后插入s结点
bool InsertNextNode(DNode *p,DNode *s)
{
s->next=p->next;
p->next->prior=s;
s->prior=p;
p->next=s;
}
2.5 静态链表
#include<stdio.h>
#define MaxSize 10 //静态链表的最大长度
typedef struct { //静态链表结构类型的定义
int data; //存储数据元素
int next; //下一个元素的数组下标
}SLinkList[MaxSize];
struct Node{
int data;
int next;
};
int main()
{
struct Node x;
printf("size-x:%d\n",sizeof(x));
struct Node a[MaxSize];
printf("size-a:%d\n",sizeof(a));
SLinkList b;
printf("size-b:%d\n",sizeof(b));
return 0;
}
output:
size-x:8
size-a:80
size-b:80
3.顺序表和链表的比较
3.1 逻辑结构
都属于线性表,都是线性结构(数据元素之间只存在一对一的关系)
3.2 存储结构
顺序表:
- 优点:支持随机存取,存储密度高
- 缺点:大片连续空间分配不方便,改变容量不方便
链表
- 优点:离散的小空间分配方便,改变容量方便
- 缺点:不可随机存取,存储密度低
3.3 基本操作
3.3.1创建:
顺序表:需要预分配大片连续空间。若分配空间过小,则之后不方便拓展容量;若分配空间过大,则浪费内存资源。即便是动态分配,容量可以改变,但是需要移动大量元素,时间代价高。
链表:只需要分配一个头结点(也可以不用头结点,只声明一个头指针),之后方便拓展
3.3.2销毁:
顺序表:
静态分配:静态数组 (系统自动回收)
动态分配:动态数组 (malloc,free) 需要手动free释放;malloc和free必须成对出现
链表:依次删除各个结点(free)
3.3.4 插入/删除:
顺序表:插入/删除元素都要将后续元素都后移/前移;时间复杂度O(n),时间开销主要来自于移动元素
若数据元素很大,则移动的时间代价很高
链表:插入/删除元素只需修改指针即可;时间复杂度O(n),时间开销主要来自于查找元素
查找元素的时间代价更低
3.3.5 查找
顺序表:
按位查找:O(1)
按值查找:O(n),若表内元素有序,可在更短时间内找到
链表:
按位查找:O(n)
按值查找:O(n)
3.4 适用场景
顺序表 | 链表 | |
---|---|---|
弹性(可扩容) | × | √ |
增、删 | × | √ |
查 | √ | × |
3.5 答题思路:
逻辑结构......
存储结构......
基本操作......
补充说明:
引用调用:
#include<iostream>
using namespace std;
void test(int x)
{
x=1024;
cout<<"x:"<<x<<endl;
}
int main()
{
int x=1;
cout<<"x:"<<x<<endl;
test(x);
cout<<"x:"<<x<<endl;
return 0;
}
//x:1
//x:1024
//x:1
#include<iostream>
using namespace std;
void test(int &x)
{
x=1024;
cout<<"x:"<<x<<endl;
}
int main()
{
int x=1;
cout<<"x:"<<x<<endl;
test(x);
cout<<"x:"<<x<<endl;
return 0;
}
//x:1
//x:1024
//x:1024
标签:结点,return,LNode,int,next,data,线性表
From: https://www.cnblogs.com/Jinx8823/p/17467534.html