注:仅供个人学习使用,来源于wangdao考研和《数据结构(严蔚敏)》,侵权必删
目录
一.顺序表的定义
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++)
L.data[i]=0; //将所有元素设置为默认初始值
L.length=0;
}
int main(){
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//...
return 0;
}
2.顺序表的动态定义
#include <stdio.h>
#include <stdlib.h>
//顺序表的定义和基本操作(动态)
#define InitSize 10 //定义最大长度
typedef struct{
int *data; //指示动态分配数组的指针
int MazSize; //顺序表的最大容量
int length; //顺序表当前的长度
}SqList; //顺序表的类型定义
//基本操作——初始化一个顺序表
void InitList(SqList &L){
//用malloc函数申请一片连续的存储空间
L.data=(int *)malloc(InitSize*sizeof(int));
L.length=0;
L.MazSize-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; //顺序表最大长度增加len
free(p); //释放原来的内存空间
}
int main(){
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//...往顺序表中随便插入几个元素。。
IncreaseSize(L,5);
return 0;
}
注:结构体相等的比较
#include<iostream>
using namespace std;
//结构体的相等“=”的比较
typedef struct{
int num;
int people;
}Customer;
void test(){
Customer a;
a.num=1;
a.people=1;
Customer b;
b.num=1;
b.people=1;
/* if(a==b){
// printf("相等");
// }
// else{
// printf("不相等");
} */
}
bool isCustomerEqual(Customer a,Customer b){
if(a.num==b.num&&a.people==b.people)
return true;
else
return false;
}
#C语言中,结构体的比较不能直接用“==”
#C++中可以使用重载运算符
#考研初试的时候,手写代码可以直接使用“==”,无论ElemType是否是结构体类型
二、单链表
1.单链表的定义
//单链表的定义
typedef struct LNode{ //定义单链表结点类型
ElemType data; //数据域,每个结点存放一个数据元素
struct LNode *next; //指针域,指针指向下一个结点
}LNode, *LinkList;
//不带头结点的单链表
//初始化一个空的单链表
bool InitList(LinkList &L){
l=NULL; //空表,暂时还没有任何结点,防止脏数据
return true;
}
//带头结点的单链表
//初始化一个单链表
bool InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode)); //分配一个头结点
if(L==NULL) //内存不足,分配失败
return false;
L->next=NULL; //头结点之后暂时还没有结点
return true;
}
void test(){
LinkList L; //声明一个指向单链表的指针 (此处并没有创建一个结点)
//初始化一个空表
InitList(L);
//...后续代码...
}
//判断单链表是否为空(不带头结点)
bool Empty(LinkList L){
if(L==NULL)
return true;
else
return false;
}
//判断单链表是否为空(带头结点)
bool Empty(LinkList L){
if(L->next==NULL)
return true;
else
return false;
}
2.单链表的插入和删除操作
#include<iostream>
using namespace std;
//单链表按位序插入和删除操作
typedef struct LNode{ //定义单链表结点类型
ElemType data; //数据域,每个结点存放一个数据元素
struct LNode *next; //指针域,指针指向下一个结点
}LNode, *LinkList;
//在第i个位置插入元素e(带头结点)
bool ListInsert(LinkList &L, int i, ElemType e){
if(i<1)
return false;
/*不带头结点
if(i==1){ //插入第1个结点的操作与其他节点操作不同
LNode *s=(LNode *)malloc(sizeof(LNode));
s->date=e;
s->next=L;
L=s;
return true;
}
LNode *p; //指针p指向当前扫描到的结点
int j=1; //当前p指向的是第几个结点
*/
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) //后插法在第i个位置上插入元素e
if(p==NULL) //i值不合法
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s; //将结点s成功连到p之后
return true; //插入成功
}
//后插操作:在p结点之后插入元素e
bool InertNextNode(LNode *p, ElemType e){
if(p==NULL)
return false;
LNode *s=(LNode*)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
//前插操作:在p节点之前插入元素e, (可以传入一个头指针LinkList L,先找到p的前驱结点,但时间复杂度O(n)
//前插操作:建立一个新的结点s作为p指针的后继结点,将p结点中的数据复制到s结点中,再用e覆盖p节点中的数据
bool InertPriorNode( 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->date; //将p中的元素复制到s中
p->data=e; //用e覆盖p中的元素
return true;
//王道书版本前插操作 直接给出了s结点前插到p结点
bool InertPriorNode( LNode *p, LNode s){
if(p==NULL|| s==NULL)
return false;
s->next=p->next;
p->next=s; //新结点s连到p之后
ElemType temp=p->data; //交换p和s的数据域
p->data=s->data;
s->data=temp;
return true;
}
//删除结点 (含头指针)
bool ListDelete(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;
if(p->next==NULL)
returm false;
LNode *q=p->next; //令q指向被删除的结点
e=q->date; //用e返回元素的值
p->next=q->next; //将*q结点从链中断开
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); //释放后继结点的存储空间
reture true;
}
3.单链表的按位序查找和按值查找
#include<iostream>
using namespace std;
//单链表按位序查找,按值查找
typedef struct LNode{ //定义单链表结点类型
ElemType data; //数据域,每个结点存放一个数据元素
struct LNode *next; //指针域,指针指向下一个结点
}LNode, *LinkList;
//按位查找,返回第i个元素(带头结点)
LNode *GetElem(LinkList L,int i) {
if(i<1)
return NULL;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //当前p指向的是第几个结点
p=L; //L指向头结点,头结点是第0个结点(不存数据)
while (p!=NULL&&j=i){ //循环找到第i个结点
p=p->next;
j++;
}
return p;
}
//可以封装成函数,然后直接在插入和删除里面使用
//LNode *p=GetElem(L,i-1);
/*王道书版本按位查找
LNode *GetElem(LinkList L, int i){
int j=1;
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;
}*/
LNode *LocateElem(LinkList L,ElemType e){
LNode *p=L->next;//从第一个节点开始查找数据域为e的结点
while (p!=NULL&&p->data!=e)
p=p->next;
return p; //找到后返回该结点指针,否则返回NULL;
}
4.单链表的建立
#include<iostream>
using namespace std;
//尾插法,头插法建立单链表
typedef struct LNode{ //定义单链表结点类型
ElemType 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;
}
void test(){
LinkList L; //声明一个指向单链表的指针
//初始化一个空表
IniyList(L);
//...后续代码
}
//后插操作:在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; //用结点s保存数据元素e
s->next=p->next;
p->next=s; //将结点s连到p之后
return true;
//尾插法建立单链表
LinkList List_TailInsert(LinkList &L){ //正向建立单链表
int x; //设ElemType为int整型
L=(LinkList)malloc(sizefo(LNode)); //建立头结点 ,初始化空表
LNode *s,*r=L; //r为表尾指针
scanf("%d",&x); //输入结点的值
while(x!=9999){ //设置一个特殊的数作为循环结束的条件
s=(LNode*)malloc(sizeof(LNode)); //在r结点之后插入x元素
s->data=x;
r->next=s; //r指向新的表尾结点
r=s;
scanf("%d",&x);
}
r->next=NULL; //尾结点指针置空
return L;
}
//头插法建立单链表
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;
}
三、双链表
#include<iostream>
using namespace std;
//双链表
typedef struct DNode{ //定义双链表结点类型 ,D是double
ElemType data; //数据域
struct DNode *prior, *next; //前驱和后继指针
}DNode, *DLinkList;
//初始化双链表
bool InitDLinkList(DLinkList &L){
L=(DNode*)malloc(sizeof(DNode)); //分配一个结点
if(L==NULL)
return false;
L->prior=NULL; //头结点的prior永远指向NULL
L->next=NULL; //头结点之后暂时还没有结点
return true;
}
void testDLinkList(){
//初始化双链表
DLinkList L;
InitDLinkList(L);
//后续代码。。。
}
//判断双链表是否为空(要带头结点)
bool Emppty(DLinkList L){
if(L->next==NULL)
return true;
else
return false;
}
//在p结点之后插入s结点
/* bool InsertNextDNode(DNode *p, DNode *s){
s->next=p->next; //将结点*s插到结点p之后
p->next->prior=s;
s->prior=p;
p->next=s;
} */
//严谨处理之后
bool InsertNextDNode(DNode *p, DNode *s){
if(p==NULL||s==NULL) //非法参数
return false;
s->next=p->next; //将结点*s插到结点p之后
if(p->next!=NULL) //如果p结点有后继节点
p->next->prior=s;
s->prior=p;
p->next=s;
return true;
}
//双链表的删除 删除p的后继结点q
/*p->next=q->next;
q->next->prior=p;
free(q);*/
//删除p的后继结点
bool DeleteDNodeLinkList(DNode *p,){
if(p==NULL)
return false;
DNode *q=p->next; //找到p结点的后继结点q
if(q==NULL) //p没有后继
return false;
p->next=q->next;
if(q->next!=NULL) //q结点不是最后一个结点
q->next->prior=q;
free(q); //释放结点空间
return true;
}
//销毁双链表
void DestroyList(DLinkList &L){
//循环释放各个数据结点
while(L->next!=NULL)
DeleteNextDNode(L);
free(L); //释放头结点
L=NULL; //头指针指向NULL
}
//双链表的遍历(后向遍历)
while(p!=NULL){
//对结点p做相应处理,如打印
p=p->next;
}
//双链表的遍历(前向遍历)
while(p!=NULL){
//对结点p做相应处理,如打印
p=p->prior;
}
//双链表的遍历(前向遍历)跳过头结点
while(p->prior!=NULL){
//对结点p做相应处理,如打印
p=p->prior;
}
//双链表不可以随机存取,按位查找(i++),按值查找(对比)操作都只能用遍历的方式 实现
四、循环链表
//循环链表:循环单链表和循环双链表
typedef struct LNode{ //定义单链表结点类型
ElemType 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;
}
//循环双链表
typedef struct DNode{ //定义双链表结点类型 ,D是double
ElemType data; //数据域
struct DNode *prior, *next; //前驱和后继指针
}DNode, *DLinkList;
//初始化循环双链表
bool InitDLinkList(DLinkList &L){
L=(DNode*)malloc(sizeof(DNode)); //分配一个结点
if(L==NULL)
return false;
L->prior=L; //头结点的prior指向头结点
L->next=L; //头结点的next指向头结点
return true;
}
void testDLinkList(){
//初始化双链表
DLinkList L;
InitDLinkList(L);
//后续代码。。。
}
//判断双链表是否为空(要带头结点)
bool Emppty(DLinkList L){
if(L->next==L)
return true;
else
return false;
}
//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinkList L, DNode *p){
if(p->next==L)
return true;
else
return false;
}
//在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s){
s->next=p->next; //将结点*s插到结点p之后
p->next->prior=s;
s->prior=p;
p->next=s;
}
//删除p的后继结点q
p->next=q->next;
q->next->prior=p;
free(q);
五、静态链表
//静态链表 ,不怎么考代码
#include<iostream>
using namespace std;
#define MazSize 10 //静态链表的最大长度
struct Node{ //静态链表结构类型的定义
ElemType data; //存储数据元素
int next; //下一个元素的数组下标
};
void testSLinkList(){
struct Node a[MaxSize] //数组a作为一个静态链表
//后续代码。。。
}
//课本上
#define MaxSize 10 //静态链表的最大长度
typedef struct{ //静态链表结构类型的定义
ELemType data; //存放数据元素
int next; //下一个元素的数组下标
}SLinkList[MazSize];
//后续用SLinkList定义变量a就是一个具有MazSize元素的数组
//并且每一个数组元素都是一个定义的结构体类型