写在开头
用于自己考研复习巩固
一、线性表基本操作
- InitList(&L)-初始化表
- Length(L)-求表长
- LocateElem(L,e)-按值查找
- GetElem(L,i)-按位查找
- ListInsert(&L,i,e)-插入
- ListDelete(&L,i,&e)-删除
- printfList(L)-输出
- Empty(L)-判空
- DestroyList(&L)-销毁
&表C/C++中的引用调用,即对参数的修改结果要带回来
二、顺序表
2.1顺序表的实现
2.1.1静态数组
#define Maxsize 50 //定义最大长度
typedef struct
{
ElemType data[Maxsize]; //静态数组存放数据元素
int length; //顺序表当前长度
} SqList;
//初始化顺序表
void InitList(SqList &L)
{
for(int i=0; i<Maxsize; i++)
L.data[i]=0; //设置默认元素初始值,不然内存会有脏数据
L.length=0; //设置初始长度为0
}
缺点:数组的大小和空间事先固定。一旦空间满,加入新的数据就会产生溢出,导致程序崩溃。
2.1.2动态分配
//动态分配
#define InitSize 50 //长度的初始定义
typedef struct
{
ElemType *data; //动态分配数值的指针
int Maxsize; //顺序表最大容量
int length; //顺序表当前长度
} SqList;
//初始化顺序表
void InitList(SqList &L)
{
//用malloc函数申请一片连续的储存空间
L.data=(ElemType *)malloc(InitSize*sizeof(ElemType ));
L.length=0;
L.MaxSize=InitSize;
//空间不够,动态增加数组长度
void Increase(SqList &L,int len)
{
int *p=L.data;
L.data=(ElemType *)malloc((L.MaxSize+len)*sizeof(ElemType ));
for(int i=0; i<L.length; i++)
L.data[i]=p[i]; //将数据复制到新区域
L.MaxSize+=len; //顺序表最大长度增加len
free(p); //释放原空间
}
2.1.3小结
2.2顺序表的插入与删除
2.2.1顺序表的插入
//顺序表的插入(以静态数组为例)(1<=i<=length+1)
bool LinkList(SqList &L,int i,ElemType e)
{
if(i<1||i>L.length+1)
return false;
if(i>=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;
}
注意数组下标和位序
2.2.2顺序表的删除
//顺序表的删除
bool ListDelete(SqList &L,int i,ElemType &e)
{
if(i<1||i>L.length)
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;
}
注意&e,把删除的值e带回来
2.2.3小结
2.3顺序表的查找
2.3.1按位查找
//按位查找
ElemType GetElem(SqList L,int i)
{
return L.data[i-1];
}
2.3.2按值查找
//按值查找
int LocateElem(SqList L,ElemType e)
{
for(int i=0; i<L.length; i++)
{
if(L.data[i]==e)
return i+1;
}
return 0;
}
1.在C语言中结构的比较不可以直接用==
2.但在《数据结构》考研初试中,手写代码可以用==,无论是基本数据类型还是结构类型
2.3.3小结
2.4易错试题
1.线性表的顺序存储结构是一种()
A.随机存取的顺序结构
B.顺序存取的顺序结构
C.索引存取的顺序结构
D.散列存取的顺序结构
A。存取方式指的是读写方式,顺序表是一种支持随机存取(在计算机科学中,随机存取(有时亦称直接访问)代表同一时间访问一组序列中的一个随意组件。)的存储结构。
三、链表
3.1单链表
3.1.1单链表的定义
3.1.1.1定义及初始化
//链表的定义
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode,*LinkList;
//初始化空的单链表
bool InitList(LinkList &L)
{
L=NULL; //防止脏数据
return true;
}
/ / 判断表空
bool Empty(LinkList L)
{
return (L==NULL);
}
//初始化带头结点的单链表
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 false;
return true;
}
LinkList 强调这是一个单链表
LNode * 强调这是一个结点
3.1.1.2小结
3.1.2单链表的插入
3.1.2.1按位序插入
//按位序插入(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<1)
return false;
LNode *p; //p指针指向当前扫描到的结点
int j=0; //p当前指向的是第几个结点
p=L; //L指向第0个结点,是头结点
while(p!=NULL&&j<i-1) //循环找到第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->next=s;
return true;
}
//按位序插入(不带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<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; //p当前指向的是第几个结点
p=L; //L指向第1个结点,不是头结点!!
//与带头结点一样
while(p!=NULL&&j<i-1) //循环找到第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->next=s;
return true;
}
带头结点的插入要注意,插入第一个要单独区别
3.1.2.2指定结点的后插
//指定结点的后插
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;
s->next=p->next;
p->next=s;
return true;
}
对3.1.2.1按位序插入中带头和不带头的相同代码部分进行封装如下:
//按位序插入(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<1)
return false;
LNode *p; //p指针指向当前扫描到的结点
int j=0; //p当前指向的是第几个结点
p=L; //L指向第0个结点,是头结点
while(p!=NULL&&j<i-1) //循环找到第i-1个结点
{
p=p->next;
j++;
}
return InsertNextNode(p,e);
}
//按位序插入(不带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
if(i<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; //p当前指向的是第几个结点
p=L; //L指向第1个结点,不是头结点!!
//与带头结点一样
while(p!=NULL&&j<i-1) //循环找到第i-1个结点
{
p=p->next;
j++;
}
return InsertNextNode(p,e);
}
3.1.2.3指定结点的前插
//指定结点的前插
bool InsertPriorNode(LNode *p,ElemType)
{
if(p==NULL)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL)
return false;
s->next=p->next;
p->next=s;
s->data=p->data;
p->data=e;
return true;
}
3.1.3单链表的删除
3.1.3.1按位序删除
//按位序删除(带头结点)
bool ListDelete(LinkList &L,int i,ElemType &e)
{
if(i<1)
return false;
LNode *p;
int j=0;
p=L;
while(p!=NULL&&j<i-1)
{
p=p->next;
j++;
}
if(p==NULL)
return false;
if(p->next==NULL)
return false;
LNode *q=p->next;
e=q->data;
p->next=q->next;
free(q);
return true;
}
//按位序删除(不带头结点)
bool ListDelete(LinkList &L,int i,ElemType &e)
{
if(i<1)
return false;
if(i==1)
{
LNode *q=L;
L=q->next;
}
LNode *p;
int j=1;
p=L;
while(p!=NULL&&j<i-1)
{
p=p->next;
j++;
}
if(p==NULL)
return false;
if(p->next==NULL)
return false;
LNode *q=p->next;
e=q->data;
p->next=q->next;
free(q);
return true;
}
3.1.3.2指定结点的删除
//指定结点的删除
bool DeleteNode(LNode *p)
{
if(p==NULL)
return false;
LNode *q=p->next;
p-data=p->next->data;
p->next=q->next;
free(q);
return true;
}
如果p是最后一个结点,只能从表头依次往后查找前驱节点,体现了单链表的局限性,无法逆向检索
3.1.3.3小结
3.1.4单链表的查找
其实在上面的插入和删除中已经涵盖了相关代码
3.1.4.1按位查找
//按位查找(带头结点)
LNode * GetElem(LinkList L,int i)
{
if(i<0)
return false;
LNode *p;
int j=0;
p=L;
while(p!=NULL&&j<i)
{
p=p->next;
j++;
}
return p;
}
可以用该函数把删除和插入中对i-1结点的查找替换为LNode * GetEle(L,i-1);
3.1.4.2按值查找
//按值查找(带头)
LNode * locateElem(LinkList L,ElemType e)
{
LNode *p=L->next;
while(p!=NULL&&p->data!=e)
p=p->next;
return p;
}
3.1.5求表长
//求表长(带头结点)
int length(LinkList L)
{
int len=0;
LNode *p=L;
while(p->next!=NULL)
{
p=p->next;
len++;
}
return len;
}
3.1.4-3.1.5小结
3.1.6单链表的建立
3.1.6.1尾插法
//尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
int x;
L=(LinkList)malloc(sizeof(LNode));
LNode *s,*r=L; //r为表尾指针
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;
}
3.1.6.2头插法
理解为对头结点进行后插法
//头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
int x;
LNode *s;
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;
scanf("%d",&x);
}
return L;
}
重点应用:链表的逆置
3.2双链表
两个指针prior和next
3.2.1定义及初始化
3.2.1.1定义
//定义双链表
typedef struct Dnode
{
ElemType data;
struct Dnode *prior,*next;
} DNode,*DLinkList;
3.2.1.2初始化
//初始化双链表
bool InitDLinkList(DLinkList &L)
{
L=(DNode *)malloc(sizeof(DNode));
if(L==NULL)
return false;
L->prior=NULL; //头结点的prior永远指向NULL
L->next=NULL;
return true;
}
3.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->next->prior=s;
s->prior=p;
p->next=s;
return true;
}
3.2.3删除
//删除p的后继结点
bool DeleteNextDNode(DNode *p)
{
if(p==NULL)
return false;
DNode *q=p->next;
if(q==NULL)
return false;
p->next=q->next;
if(q->next!=NULL)
q->next->prior=p;
free(q);
return true;
}
3.2.4小结
3.3循环链表
3.3.1初始化循环单链表
//循环单链表的初始化
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;
return false;
}
3.3.2初始化循环双链表
//循环双链表的初始化
bool InitDLinkList(DLinkList &L)
{
L=(DNode *)malloc(sizeof(DNode));
if(L==NULL)
return false;
L->prior=L;
L->next=L;
return true;
}
//判断空表
bool Empty(DLinkList L)
{
if(L->next=L)
return true;
return false;
}
3.3.3小结
3.4静态链表
3.4.1定义
//静态链表的定义
#define MaxSize 10
typedef struct
{
ElemType data;
int next;
} SLinkList[MaxSize];
四、顺序表和链表比较
五、写在最后
付出,才有收获!