数据结构——第二章 线性表

其他数据结构

目录

前言

1 线性表

2 线性表的顺序存储——顺序表

3 线性表的链式存储

3.1 单链表

3.2 双向链表

3.3 循环链表

3.4 静态链表

前言

逻辑结构:线性表

存储结构:顺序存储结构(简称顺序表)和链式存储结构(简称链表)

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;
} 

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值