数据结构(链表)

文章目录

  • 一、单链表
    • 1、单链表定义
    • 2、初始化单链表
      • 2.1、不带头结点的单链表
      • 2.2、带头结点的单链表
    • 3、单链表基本操作
      • 3.1、按位序插入(带头结点)
      • 3.2、按位序插入(不带头结点)
      • 3.3、指定结点的后插操作
      • 3.4、指定结点的前插操作
      • 3.5、按位序删除(带头结点)
      • 3.6、指定结点的删除
      • 3.7、按位查找
      • 3.8、按值查找
    • 4、单链表的建立
      • 4.1、尾插法
      • 4.2、头插法
  • 二、双链表
    • 1、双链表的初始化(带头结点)
    • 2、插入
    • 3、删除
    • 4、遍历
  • 三、循环链表
    • 3.2、循环双链表
  • 四、静态链表
    • 4.1、基本操作
  • 顺序表和链表的比较

一、单链表

1、单链表定义

数据结构(链表)_第1张图片
typedef重命名数据类型
数据结构(链表)_第2张图片
第二种声明方式可读性更强
数据结构(链表)_第3张图片
LinkList和LNode*的不同用法
数据结构(链表)_第4张图片

#include

//定义单链表结点类型 
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode,*LinkList; 

//查找单链表中的某一个位置的数
LNode* GetElem(LinkList L,int i){
	int j=1;
	LNode *p=L->next;
	if(i==0)
		return L;
	if(i<1)
		return NULL;
	if(p!=NULL&&j<i){
		p=p->next;
		j++;
	} 
	return p;
} 
 


2、初始化单链表

2.1、不带头结点的单链表

数据结构(链表)_第5张图片

//定义单链表结点类型 
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode,*LinkList; 

//初始化一个空的单链表
bool InitList(LinkList &L){
	L=NULL;
	return true;
} 

//判断单链表是否为空
bool Empty(LinkList L){
	return(L==NULL);
} 

2.2、带头结点的单链表

数据结构(链表)_第6张图片

//定义单链表结点类型 
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){
	return(L->next==NULL);
} 
int main(){
	LinkList L;
	InitList(L);
	return 0;
}

大多数情况使用带头结点的方式
数据结构(链表)_第7张图片
数据结构(链表)_第8张图片

3、单链表基本操作

3.1、按位序插入(带头结点)

数据结构(链表)_第9张图片
带头结点插入位置1时
数据结构(链表)_第10张图片
数据结构(链表)_第11张图片

//插入操作
bool ListInsert(LinkList &L,int i,int e){
	if(i<1)
		return false;
	LNode *p;
	p=L;
	int j=0;
	//找到i-1位置 
	while(p!=NULL&&j<i-1){
		p=p->next;
		j++;
	}
	//开拓新区域 
	 LNode *s=(LNode*)malloc(sizeof(LNode));
	 s->data=e;
	 s->next=p->next;
	 p->next=s;
	 return true;
} 

在这里插入图片描述

3.2、按位序插入(不带头结点)

数据结构(链表)_第12张图片

bool ListInsert(LinkList &L,int i,int e){
	if(i<1)
		return false;
	if(i==1){//不同的地方 
		LNode*s=(LNode*)malloc(sizeof(LNode));
		s->data=e;
		s->next=L;//因为L没有next所以直接等于
		L=s; //头指针指向新结点 
		return true; 
	}
	LNode *p;
	p=L;
	int j=0;
	//找到i-1位置 
	while(p!=NULL&&j<i-1){
		p=p->next;
		j++;
	}
	//开拓新区域 
	 LNode *s=(LNode*)malloc(sizeof(LNode));
	 s->data=e;
	 s->next=p->next;
	 p->next=s;
	 return true;
} 

3.3、指定结点的后插操作

数据结构(链表)_第13张图片

数据结构(链表)_第14张图片

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;
	s->next=p->next;
	p->next=s;
	return true;	
}

3.4、指定结点的前插操作

前面区域无法访问,只能把头结点传入
数据结构(链表)_第15张图片
将p的值赋值给s,再将插入的值赋值给p
数据结构(链表)_第16张图片

bool InsertPriorNode(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->data=p->data;
	p->data=e;
	return true;	
}

3.5、按位序删除(带头结点)

数据结构(链表)_第17张图片
数据结构(链表)_第18张图片
在这里插入图片描述

bool ListDelete(LinkList &L,int i,int &e){
	if(i<1)
		return false;
	LNode *p;
	p=L;
	int j=0;
	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;//q指向被删除的结点 
	e=q->data;//保存删除的值 
	p->next=q->next;//断开q 
	free(q);//销毁q 
	return true; 
}

3.6、指定结点的删除

如果删除最后一个元素,就会出错
数据结构(链表)_第19张图片
数据结构(链表)_第20张图片

3.7、按位查找

数据结构(链表)_第21张图片

LNode *GetElem(LinkList L,int i){
	if(i<1)
		return false;
	LNode *p;
	p=L;
	int j=0;
	while(p!=NULL&&j<i-1){
		p=p->next;
		j++; 
	}
	return p;
} 

数据结构(链表)_第22张图片

3.8、按值查找

数据结构(链表)_第23张图片
数据结构(链表)_第24张图片
数据结构(链表)_第25张图片

4、单链表的建立

数据结构(链表)_第26张图片

4.1、尾插法

数据结构(链表)_第27张图片

LinkList List_TailInsert(LinkList &L){
	int x;
	L=(LNode*)malloc(sizeof(LNode));
	L->next=NULL;
	LNode *s,*r=L;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode*)malloc(sizeof(LNode));
		r->next=s;
		s->data=x;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}

4.2、头插法

链表的逆置
数据结构(链表)_第28张图片

LinkList List_TailInsert(LinkList &L){
	LNode *s;
	int x;
	L=(LNode*)malloc(sizeof(LNode));
	L->next=NULL;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode*)malloc(sizeof(LNode));
		s->next=L->next;
		L->next=s;
		scanf("%d",&x);
	}
	return L;
}

二、双链表

1、双链表的初始化(带头结点)

数据结构(链表)_第29张图片
数据结构(链表)_第30张图片

bool InitDLinkList(DLinkList &L){
	L=(DNode*)malloc(sizeof(DNode));
	L->next=NULL;
	L->prior=NULL;
	return true;
} 

2、插入

数据结构(链表)_第31张图片
数据结构(链表)_第32张图片

bool InsertNextDNode(DNode *p,DNode *s){
	s->next=p->next;
	if(p->next!=NULL)
		p->next->prior=s;
	s->prior=p;
	p->next=s;
}

3、删除

数据结构(链表)_第33张图片

4、遍历

数据结构(链表)_第34张图片
数据结构(链表)_第35张图片

三、循环链表

数据结构(链表)_第36张图片
数据结构(链表)_第37张图片

3.2、循环双链表

数据结构(链表)_第38张图片
数据结构(链表)_第39张图片
双链表,在尾部插入数据时,双链表会在第二行p->next->prior=s出错,因为p->next为空,但是循环后就不为空了
数据结构(链表)_第40张图片
数据结构(链表)_第41张图片

四、静态链表

数据结构(链表)_第42张图片
数据结构(链表)_第43张图片
数据结构(链表)_第44张图片

#include
#define MaxSize 10

//常规 
struct Node{
	int data;
	int next;
}; 
//课本 
typedef struct{
	int data;
	int next;
}SLinkList[MaxSize];

int main(){

	struct Node x;
	printf("%d\n",sizeof(x));
	//常规
	struct Node a[MaxSize];
	printf("%d\n",sizeof(a)); 
	SLinkList b;
	printf("%d\n",sizeof(b)); 	
}

4.1、基本操作

数据结构(链表)_第45张图片
数据结构(链表)_第46张图片
优点:
增、删操作不需要大量移动元素
缺点:
不能随机存取,只能从头结点开始依次往后查找;容量固定不可变
适用场景:
①不支持指针的低级语言;
②数据元素数量固定不变的场景(如操作系统的文件分配表FAT)

顺序表和链表的比较

存储结构
数据结构(链表)_第47张图片
数据结构(链表)_第48张图片
数据结构(链表)_第49张图片
数据结构(链表)_第50张图片
数据结构(链表)_第51张图片
表长难以预估、经常要增加/删除元素——链表
表长可预估、查询(搜索)操作较多——顺序表

你可能感兴趣的:(蓝桥杯,数据结构,链表)