目录
前言
逻辑结构:线性表
存储结构:顺序存储结构(简称顺序表)和链式存储结构(简称链表)
1 线性表
线性表中的位序从1开始
2 线性表的顺序存储——顺序表
顺序表用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。
静态分配
#define MaxSize 50
typedef struct{
//ElempType为元素类型,如int,float等
ElempType data[MaxSize];//地址连续
int length;
}SqList;
静态分配的初始化方法InitList(SqList &L)
void InitList(SqList &L){
int length=0;//初始时顺序表的长度为0,没有元素
}
静态分配与动态分配的区别是动态分配可以增加顺序表的容量,以下对动态分配进行讲解: (ElemType为数据类型,Status为函数的类型)
动态分配
#define InitSize 100
typedef struct{
ElemType *data;//引入指针,指向首地址
int length;
int MaxSize;
}SqList;
1、动态分配的初始化方法InitList(SqList &L)
//初始化
void InitList(SqList &L){
L.data=malloc(Initsize*sizeof(ElemType));//将data指向开辟的空间
L.length=0;
L.MaxSize=InitSize;
}
2、动态分配增加顺序表容量IncreaseSize(SqList &L,int len)
//扩大顺序表的容量
void IncreaseList(SqList &L,int len){
ElemType *p=L.data;//将p指针指向原来的顺序表
L.data=malloc((MaxSize+len)*sizeof(ElemType));//data指针指向新开辟的更大的空间
for(int i=0;i<MaxSize;i++){
L.data[i]=p[i];//将原来的数据复制回来
}
MaxSize+=len;
free(p);//释放原来的连续空间
}
3、查找元素的位置LocateElem(SqList L,int e)
//查找元素的位置
int LocateElem(SqList L,ElemType e){
for(int i=0;i<L.length;i++){
if(L.data[i]==e){
return i+1;
}
}
return -1;
}
4、查找位置i的元素GetElem(SqList L,int i)
Status GetElem(SqList L,int i){
if(i<1||i>L.length) return -1;
return L.data[i-1];
}
5、在位置x插入元素e:IncreaseElem(SqList &L,int x,ElemType e)
//插入元素
bool IncreaseElem(SqList &L,int x,ElemType e){
if(x<1||x>L.length+1) return false;
if(L.length==L.MaxSize) return false;
for(int i=L.length-1;i>=x-1;i++){
L.data[i+1]=L.data[i];
}
L.data[x-1]=e;
L.length+=1;
return true;
}
6、删除位置x的元素DeleteElem(SqList &L,int x,ElemType &e)
//删除元素
bool DeleteElem(SqList &L,int x,ElemType &e){
e=L.data[x-1];
if(x<1||x>L.length) return false;
for(int i=x;i<L.length;i++){
L.data[i-1]=L.data[i];
}
L.length-=1;
return true;
}
7、展示
//展示
void printList(SqList L){
for(int i=0;i<L.length;i++){
printf("%d ",L.data[i]);
}
printf("\n");
}
8、判空
//判空
bool Empty(SqList L){
if(L.length==0){
return true;
}else{
return false;
}
}
9、销毁
//销毁
void DestroyList(SqList &L){
free(L.data);
}
10、当ElemType为int时,动态分配具体实现:
#include<stdio.h>
#include<stdlib.h>
#define InitSize 100
typedef int ElemType;
typedef struct{
int *data;
int length;
int MaxSize;
}SeqList;
//初始化
void InitList(SeqList &L){
L.data=(int *)malloc(InitSize*sizeof(ElemType));
L.length=0;
L.MaxSize=InitSize;
}
//扩大顺序表的容量
void IncreaseSize(SeqList &L,int len){
int *q=L.data;
L.data=(ElemType *)malloc((InitSize+len)*sizeof(ElemType));
for(int i=0;i<=L.length;i++){
L.data[i]=q[i];
}
L.MaxSize=L.MaxSize+len;
free(q);
}
//查找元素的位置
int LocateElem(SeqList L,int e){
for(int i=0;i<L.length;i++){
if(L.data[i]==e)
return i+1;
}
return -1;
}
//获取位置i上的元素
ElemType GetElem(SeqList L,int i){
if(i<1||i>L.length)
return -1;
return L.data[i-1];
}
//插入元素
bool ListInsert(SeqList &L,int i,ElemType e){
if(i<1||i>L.length+1)
return false;
if(L.MaxSize<=L.length)
return false;
for(int j=L.length-1;j>=i-1;j--){
L.data[j+1]=L.data[j];
}
L.data[i-1]=e;
L.length++;
return true;
}
//删除元素
bool ListDelete(SeqList &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;
}
//展示
void PrintList(SeqList L){
for(int i=0;i<L.length;i++){
printf("%d ",L.data[i]);
}
printf("\n");
}
//判空
bool Empty(SeqList L){
if(L.length==0)
return true;
return false;
}
//销毁
void DestroyList(SeqList &L){
free(L.data);
}
int main(){
SeqList L;
printf("--------------初始化----------------\n");
InitList(L);
printf("顺序表的长度:%d\n",L.length);
printf("-----------------插入-------------------\n");
printf("插入10个数:\n");
for(int i=1;i<=10;i++){
ListInsert(L,i,i);
}
PrintList(L);
printf("-----------------删除-------------------\n");
ElemType e=0;
printf("删除第一个数:\n");
ListDelete(L,1,e);
PrintList(L);
printf("删除的数是:%d\n",e);
printf("-----------------扩大容量-------------------\n");
printf("当前容量:%d\n",L.MaxSize);
IncreaseSize(L,100);
printf("扩大100:%d\n",L.MaxSize);
printf("-----------------获取位置i上的元素-----------------\n");
printf("获取顺序表的第三个元素:%d\n",GetElem(L,3));
printf("-----------------查找元素的位置 -----------------\n");
if(LocateElem(L,3)!=-1){
printf("查找3的位置:%d\n",LocateElem(L,3));
}else{
printf("没有该元素!\n");
}
return 0;
}
3 线性表的链式存储
3.1 单链表
带头结点
typedef struct LNode{
ElemType data;
struct node *next;
}LNode,*LinkList;
//初始化
void InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
}
带头结点的单链表具体实现:
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化(创建只有一个头结点的空链表)
void InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
}
//头插法建立单链表
void CreateList_H(LinkList &L){
//初始化一个空链表,可以用InitList(LinkList &L)代替
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
//头插
LNode *s;
int x;
printf("请输入单链表的数据域(输入9999表示结束)\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
}
//尾插法建立单链表
void CreateList_R(LinkList &L){
//初始化一个空链表
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
//尾插法
LNode *s,*r;
int x;
r=L;//指向最后一个结点
printf("请输入单链表的数据域(输入9999表示结束)\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
s->next=NULL;
r->next=s;
r=s;
scanf("%d",&x);
}
}
//判空
bool Empty(LinkList L){
return L->next==NULL;
}
//输出单链表
void print_LinkList(LinkList L){
LNode *p=L->next;
while(p){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
//单链表的取值
LNode *GetElem(LinkList L,int i){
LNode *p=L->next;
int j=1;
if(i==0) return L;
if(i<0) return NULL;
while(p&&j<i){
p=p->next;
j++;
}
return p;
}
//按值查找
LNode *LocateElem(LinkList L,int e){
LNode *p=L->next;
while(p&&p->data!=e){
p=p->next;
}
return p;
}
//插入(在位置i上插)
void ListInsert(LinkList &L,int i,int e){
LNode *p=GetElem(L,i-1);
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
}
//前插(给定结点,要进行前插,可以进行后插,然后交换数据域,时间复杂度仅为O(1))
void AfterInsert(LNode *p,int e){
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=p->data;
s->next=p->next;
p->next=s;
p->data=e;
}
//删除 (删除位置i上的结点)
void ListDelete(LinkList &L,int i,int &e){
LNode *p=GetElem(L,i-1);
LNode *q=p->next;
e=q->data;
p->next=q->next;
free(q);
}
//删除给定结点(和后继结点交换数据域,然后删除后继结点)注意:不能是尾结点
void DeleteLNode(LNode *p){
//q为下一个
LNode *q=p->next;
p->data=q->data;
p->next=q->next;
free(q);
}
//求表长
int LinkLength(LinkList L){
LNode *p=L->next;
int count=0;
while(p){
count++;
p=p->next;
}
return count;
}
int main(){
LinkList L;
printf("------------------头插法创建单链表(与输入倒序)-------------------\n");
CreateList_H(L);
printf("创建完成:");
print_LinkList(L);
printf("------------------插入-------------------\n");
printf("在位置2上插入,数据域为10:\n");
ListInsert(L,2,10);
print_LinkList(L);
printf("------------------删除-------------------\n");
printf("删除第1个:\n");
int e=0;
ListDelete(L,1,e);
print_LinkList(L);
printf("删除的数是:%d\n",e);
printf("------------------取值-------------------\n");
printf("第一个结点的数据域是:\n");
LNode *p=GetElem(L,1);
printf("%d\n",p->data);
printf("------------------按值查找-------------------\n");
printf("数据域为3的结点q地址:\n");
LNode *q=LocateElem(L,3);
printf("%p\n",q);
printf("------------------前插-------------------\n");
printf("在结点q前面插入数据域为20的结点:\n");
AfterInsert(q,20);
print_LinkList(L);
printf("------------------删除给定结点-------------------\n");
printf("删除给定的第一个结点:\n");
DeleteLNode(p);
print_LinkList(L);
printf("------------------求表长-------------------\n");
printf("链表长度:%d\n",LinkLength(L));
printf("------------------尾插法创建单链表(与输入相同)-------------------\n");
LinkList L2;
CreateList_R(L2);
printf("创建完成:");
print_LinkList(L2);
return 0;
}
不带头结点
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化
void InitLinkList(LinkList &L){
L=NULL;
}
不带头结点的单链表的具体实现:(给出了创建方法,其他基本方法与带头结点的类似)
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化
void InitLinkList(LinkList &L){
L=NULL;
}
//判空
bool Empty(LinkList L){
return L==NULL;
}
//头插法建立单链表
void CreateList_H(LinkList &L){
L=NULL;
//头插
LNode *s;
int x;
printf("请输入单链表的数据域(输入9999表示结束)\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
s->next=L;
L=s;
scanf("%d",&x);
}
}
//尾插法建立单链表
void CreateList_R(LinkList &L){
L=NULL;
//尾插
LNode *s,*r=L;
int x;
printf("请输入单链表的数据域(输入9999表示结束)\n");
scanf("%d",&x);
while(x!=9999){
if(L==NULL){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
s->next=NULL;
L=s;
r=s;
}else{
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
s->next=NULL;
r->next=s;
r=s;
}
scanf("%d",&x);
}
}
//输出
void printfList(LinkList L){
LNode *p=L;
while(p){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
int main(){
LinkList L;
printf("-----------------头插法建立单链表--------------------\n");
CreateList_H(L);
printf("创建完成:\n");
printfList(L);
printf("-----------------尾插法建立单链表--------------------\n");
LinkList L2;
CreateList_R(L2);
printf("创建完成:\n");
printfList(L2);
return 0;
}
3.2 双向链表
带头结点
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
初始化
//初始化
void InitDLinkList(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
L->prior=NULL;
L->next=NULL;
}
带头结点的双向链表的具体实现:
#include<iostream>
using namespace std;
typedef int ElemType;
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
//初始化
void InitDLinkList(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
L->prior=NULL;
L->next=NULL;
}
//判断双链表是否为空
bool Empty(DLinkList L){
if(L->next==NULL) return true;
return false;
}
//在p结点之后插入s结点 注意:p不能是尾结点
bool InsertNextNode(DNode *p,DNode *s){
if(p==NULL||s==NULL) return false;
s->next=p->next;
if(p->next!=NULL) p->next->prior=s;//如果p有后继结点
s->prior=p;
p->next=s;
return true;
}
//删除p的后继结点 注意: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;//如果q结点不是最后一个结点
free(q);
return true;
}
//销毁双向链表
void DestoryList(DLinkList &L){
//循环释放各个数据结点
while(L->next!=NULL){
DeleteNextDNode(L);//一直删头结点后面的结点
}
free(L);
L=NULL;
}
int main(){
DLinkList L;
InitDLinkList(L);
cout<<Empty(L)<<endl;
return 0;
}
3.3 循环链表
3.3.1 循环单链表(带头结点)
单链表从一个结点出发只能找到后续的各个结点,而循环单链表从一个结点出发可以找到其他任何一个结点。
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
初始化
//初始化一个循环单链表
void InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
L->next=L;
}
具体实现:
#include<iostream>
using namespace std;
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化一个循环单链表
void InitLinkList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
L->next=L;
}
//判空
bool Empty(LinkList L){
if(L->next==L){
return true;
}else{
return false;
}
}
int main(){
LinkList L;
InitLinkList(L);
cout<<Empty(L)<<endl;
return 0;
}
3.3.2 循环双链表(带头结点)
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
初始化
//初始化一个循环双链表
void InitDLinkList(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
L->prior=L;
L->next=L;
}
具体实现:
#include<iostream>
using namespace std;
typedef int ElemType;
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
//初始化一个循环双链表
void InitDLinkList(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
L->prior=L;
L->next=L;
}
//判空
bool Empty(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结点 p可以尾结点
bool InsertNextNode(DNode *p,DNode *s){
if(p==NULL||s==NULL) return false;
s->next=p->next;//如果p有后继结点
s->prior=p;
p->next=s;
return true;
}
//删除p的后继结点 p可以是尾结点或倒数第二个结点
bool DeleteNextDNode(DNode *p){
if(p==NULL) return false;
DNode *q=p->next;
p->next=q->next;
q->next->prior=p;
free(q);
return true;
}
int main(){
DLinkList L;
InitDLinkList(L);
cout<<Empty(L)<<endl;
return 0;
}
3.4 静态链表
分配一整片连续的内存空间,各个结点集中安置。
typedef struct Node{
ElemType data;
int next;
}Node,SLinkList[MaxSize];
初始化
//静态链表的初始化
void InitSLinkList(SLinkList &L){
L[0].next=-1;
}
具体实现:
#include<iostream>
using namespace std;
#define MaxSize 10
typedef int ElemType;
typedef struct Node{
ElemType data;
int next;
}Node,SLinkList[MaxSize];
//静态链表的初始化
void InitSLinkList(SLinkList &L){
L[0].next=-1;
}
int main(){
SLinkList L;
return 0;
}