数据结构——单向循环链表、双链表、双向循环链表

目录

一、单向循环链表

[1.1 单向循环链表的概念](#1.1 单向循环链表的概念)

[1.2 单向循环链表的操作](#1.2 单向循环链表的操作)

[1.2.1 单向循环链表的创建](#1.2.1 单向循环链表的创建)

[1.2.2 单向循环链表的头插](#1.2.2 单向循环链表的头插)

[1.2.3 单向循环链表的遍历](#1.2.3 单向循环链表的遍历)

[1.2.4 单向循环链表的头删](#1.2.4 单向循环链表的头删)

[1.2.5 单向循环链表的尾插](#1.2.5 单向循环链表的尾插)

[1.2.6 单向循环链表的尾删](#1.2.6 单向循环链表的尾删)

[1.2.7 约瑟夫环](#1.2.7 约瑟夫环)

[1.3 单向循环列表所有程序](#1.3 单向循环列表所有程序)

[1.3.1 head.h](#1.3.1 head.h)

[1.3.2 main.c](#1.3.2 main.c)

[1.3.3 fun.c](#1.3.3 fun.c)

[1.4 输出效果](#1.4 输出效果)

二、双链表

[2.1 双链表的概念](#2.1 双链表的概念)

[2.2 双链表的操作](#2.2 双链表的操作)

[2.2.1 双链表的创建](#2.2.1 双链表的创建)

[2.2.2 双链表的头插](#2.2.2 双链表的头插)

[2.2.3 双链表的遍历](#2.2.3 双链表的遍历)

[2.2.4 双链表的头删](#2.2.4 双链表的头删)

[2.2.5 双链表的尾插](#2.2.5 双链表的尾插)

[2.2.6 双链表的尾删](#2.2.6 双链表的尾删)

[2.3 双链表所有程序](#2.3 双链表所有程序)

[2.3.1 head.h](#2.3.1 head.h)

[2.3.2 main.c](#2.3.2 main.c)

[2.3.3 fun.c](#2.3.3 fun.c)

[2.4 输出效果](#2.4 输出效果)

三、双向循环列表

[3.1 双向循环链表的概念](#3.1 双向循环链表的概念)

[3.2 双向循环链表的操作](#3.2 双向循环链表的操作)

[3.2.1 双向循环链表的创建](#3.2.1 双向循环链表的创建)

[3.2.2 双向循环链表的头插](#3.2.2 双向循环链表的头插)

[3.2.3 双向循环链表的遍历](#3.2.3 双向循环链表的遍历)

[3.2.4 双向循环链表的头删](#3.2.4 双向循环链表的头删)

[3.2.5 双向循环链表的尾插](#3.2.5 双向循环链表的尾插)

[3.2.6 双向循环链表的尾删](#3.2.6 双向循环链表的尾删)

[3.3 双向循环链表所有程序](#3.3 双向循环链表所有程序)

[3.3.1 head.h](#3.3.1 head.h)

[3.3.2 main.c](#3.3.2 main.c)

[3.3.3 fun.c](#3.3.3 fun.c)

[3.4 输出效果](#3.4 输出效果)


一、单向循环链表

1.1 单向循环链表的概念

1.单向循环链表:尾节点的指针域指向头结点的地址

2.单向循环链表的节点:数据域和指针域

数据域:存储的数据元素

指针域:存储节点之间的关系,下一个节点的地址,单向循环链表的指针域指向该节点的地址

1.2 单向循环链表的操作

1.2.1 单向循环链表的创建

cpp 复制代码
// 创建单向循环链表---------------
Linklist creat_node()
{
	// 1.创建一个新的节点
	Linklist s=(Linklist)malloc(sizeof(struct Node));
	// 2. 
	if(NULL==s)
		return NULL;
	// 初始化新节点的数据域
	s->data=0;
	// 初始化新节点的指针域
	s->next=s;
	return s;
}

1.2.2 单向循环链表的头插

cpp 复制代码
// 头插---------------
Linklist insert_head(Linklist head,datatype element)
{
	Linklist s=creat_node();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
		head=s;
	else  // 链表中存在多个节点 >=1
	{
		// 找到尾节点
		Linklist del=head;
		while(del->next!=head)
		{
			del=del->next;
		}
		s->next=head;
		head=s;
		del->next=head;
	}
	return head;
}

1.2.3 单向循环链表的遍历

cpp 复制代码
// 循环遍历---------------
void output(Linklist head)
{
	//  1.判断链表是否为空
	if(NULL==head)
		return;
	// 2.循环遍历
	Linklist p=head;
	printf("Linklist=");
	do
	{
		printf("%d ",p->data);
		p=p->next;
	}while(p!=head);
	putchar(10);
	return;
}

1.2.4 单向循环链表的头删

cpp 复制代码
// 单向循环链表的头删---------------
Linklist delete_head(Linklist head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表是否为1
	if(head->next==head)
	{
		free(head);
		head=NULL;
		return head;
	}
	// 3.头删
	//  找到尾节点
	Linklist real=head;
	while(real->next!=head)
	{
		real=real->next;
	}
	Linklist del;
	del=head;
	head=head->next;
	free(del);
	del=NULL;
	real->next=head;
	return head;
}

1.2.5 单向循环链表的尾插

cpp 复制代码
// 单向循环链表的尾插---------------
Linklist insert_tail(Linklist head,datatype element)
{
	// 1.创建新节点,并输入值
	Linklist s=creat_node();
	s->data=element;
	s->next=head;
	// 2.判断链表是否为空
	if(NULL==head)
	{
		head=s;
	}
	else
	{
		// 3.尾插
		Linklist p=head;
		while(p->next!=head)  // 找到最后一个节点
		{
			p=p->next;
		}
		p->next=s;  // 链接:p指针域指向新节点的地址
	}
	return head;
}

1.2.6 单向循环链表的尾删

cpp 复制代码
// 单向循环链表的尾删---------------
Linklist delete_tail(Linklist head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.只有一个节点时
	else if(head->next==head)
	{
		free(head);
		head=NULL;
	}
	// 3.有多个节点时
	else
	{
		Linklist del=head;
		// 找到倒数第二个节点
		while(del->next->next!=head)
		{
			del=del->next;
		}
		// 删除p的后继
		free(del->next);
		del->next=head;
	}
		return head;
}

1.2.7 约瑟夫环

约瑟夫环:用循环链表编程实现约瑟夫问题

n个人围成一圈,从某人开始报数1, 2, ..., m,数到m的人出圈,然后从出圈的下一个人(m+1)开始重复此过程,直到 全部人出圈,于是得到一个出圈人员的新序列

如当n=8,m=4时,若从第一个位置数起,则所得到的新的序列 为4, 8, 5, 2, 1, 3, 7, 6。

cpp 复制代码
// 约瑟夫环
Linklist joseph(Linklist head,int n, int m)
{
	Linklist p=head;
	Linklist del=NULL;
	Linklist s=NULL;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<m-1;j++)
		{
			p=p->next;
		}
		del=p->next;
		p->next=p->next->next;
		p=p->next;
		if(i==1)
		{
			head=del;
			head->next=head;
		}
		else
		{
			s=head;
			while(s->next!=head)
			{
				s=s->next;
			}
			del->next=head;
			s->next=del;
		}
	}
	return head;
}

1.3 单向循环列表所有程序

1.3.1 head.h

cpp 复制代码
#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int datatype;
enum passble{SUCCSSES,FALSE=-1};
// 节点结构定义
// 节点:数据、指针域
// Node不可省略
typedef struct Node
{
	datatype data;  // 数据域:数据元素
	struct Node *next;  // 指针域:节点之间的关系,下一个节点的地址
}*Linklist;

Linklist creat_node();
Linklist insert_head(Linklist head,datatype element);
void output(Linklist head);
Linklist delete_head(Linklist);
Linklist insert_tail(Linklist head,datatype element);
Linklist delete_tail(Linklist head);
int get_len(Linklist head);
Linklist joseph(Linklist head,int n, int m);

#endif

1.3.2 main.c

cpp 复制代码
#include "head.h"
int main(int argc, const char *argv[])
{
// 单向循环链表的创建
// 单向循环链表的头插
	Linklist head=NULL;
	int n;
	printf("请输入插入个数:");
	scanf("%d",&n);
	datatype element;
	for(int i=0;i<n;i++)
	{
		printf("请输入插入的第 %d 个元素:",i+1);
		scanf("%d",&element);
		head=insert_head(head,element);
	}
	output(head);

// 单向循环链表的头删
	head=delete_head(head);
	printf("头删后");
	output(head);
// 单向循环链表的尾插
	printf("请输入尾插个数:");
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		printf("请输入尾插元素:");
		scanf("%d",&element);
		head=insert_tail(head,element);
	}
	output(head);

// 单向循环链表的尾删
	head=delete_tail(head);
	printf("尾删后");
	output(head);
	
// 约瑟夫环
	int m=4;
	head=joseph(head,n,m);
	output(head);

	return 0;
}

1.3.3 fun.c

cpp 复制代码
#include "head.h"
// 创建单向循环链表---------------
Linklist creat_node()
{
	// 1.创建一个新的节点
	Linklist s=(Linklist)malloc(sizeof(struct Node));
	// 2. 
	if(NULL==s)
		return NULL;
	// 初始化新节点的数据域
	s->data=0;
	// 初始化新节点的指针域
	s->next=s;
	return s;
}
// 头插---------------
Linklist insert_head(Linklist head,datatype element)
{
	Linklist s=creat_node();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
		head=s;
	else  // 链表中存在多个节点 >=1
	{
		// 找到尾节点
		Linklist del=head;
		while(del->next!=head)
		{
			del=del->next;
		}
		s->next=head;
		head=s;
		del->next=head;
	}
	return head;
}

// 循环遍历---------------
void output(Linklist head)
{
	//  1.判断链表是否为空
	if(NULL==head)
		return;
	// 2.循环遍历
	Linklist p=head;
	printf("Linklist=");
	do
	{
		printf("%d ",p->data);
		p=p->next;
	}while(p!=head);
	putchar(10);
	return;
}
// 单向循环链表的头删---------------
Linklist delete_head(Linklist head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表是否为1
	if(head->next==head)
	{
		free(head);
		head=NULL;
		return head;
	}
	// 3.头删
	//  找到尾节点
	Linklist real=head;
	while(real->next!=head)
	{
		real=real->next;
	}
	Linklist del;
	del=head;
	head=head->next;
	free(del);
	del=NULL;
	real->next=head;
	return head;
}
// 单向循环链表的尾插---------------
Linklist insert_tail(Linklist head,datatype element)
{
	// 1.创建新节点,并输入值
	Linklist s=creat_node();
	s->data=element;
	s->next=head;
	// 2.判断链表是否为空
	if(NULL==head)
	{
		head=s;
	}
	else
	{
		// 3.尾插
		Linklist p=head;
		while(p->next!=head)  // 找到最后一个节点
		{
			p=p->next;
		}
		p->next=s;  // 链接:p指针域指向新节点的地址
	}
	return head;
}
// 单向循环链表的尾删---------------
Linklist delete_tail(Linklist head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.只有一个节点时
	else if(head->next==head)
	{
		free(head);
		head=NULL;
	}
	// 3.有多个节点时
	else
	{
		Linklist del=head;
		// 找到倒数第二个节点
		while(del->next->next!=head)
		{
			del=del->next;
		}
		// 删除p的后继
		free(del->next);
		del->next=head;
	}
		return head;
}

// 约瑟夫环
Linklist joseph(Linklist head,int n, int m)
{
	Linklist p=head;
	Linklist del=NULL;
	Linklist s=NULL;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<m-1;j++)
		{
			p=p->next;
		}
		del=p->next;
		p->next=p->next->next;
		p=p->next;
		if(i==1)
		{
			head=del;
			head->next=head;
		}
		else
		{
			s=head;
			while(s->next!=head)
			{
				s=s->next;
			}
			del->next=head;
			s->next=del;
		}
	}
	return head;
}

1.4 输出效果

二、双链表

2.1 双链表的概念

引入目的:无论是单向循环或单向链表,只能向后遍历吗,不可以向前访问,引出双链表

1.双向链表:链表既可以向前访问也可以向后访问

2.双向链表的节点

3.双向链表节点的结构体定义

结构体:数据域,两个指针域

4.双向链表插入和删除的思想

2.2 双链表的操作

2.2.1 双链表的创建

cpp 复制代码
// 创建节点
Doublelink creat_link()
{
	Doublelink s=(Doublelink)malloc(sizeof(struct Node));
	if(NULL==s)
		return NULL;
	s->data=0;  // 新节点的数据域初始化
	s->next=NULL;  // 新节点的指针域初始化
	s->last=NULL;
	return s;
}

2.2.2 双链表的头插

cpp 复制代码
// 双向列表的头插
Doublelink insert_head(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s;
		return head;
	}
	// 2.链表不为空,存在多个节点
	s->next=head;  // 新节点的next指向头节点
	head->last=s;  // 头结点的last指向新节点
	head=s; // 使新节点成为头结点
	return head;
}

2.2.3 双链表的遍历

cpp 复制代码
// 双向列表的遍历
void outlink(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return;
	// 2.链表不为空
	else
	{
		Doublelink p=head;
		printf("正向遍历 Doublelink= ");
		while(p->next!=NULL)
		{
			printf("%c ",p->data);
			p=p->next;
		}
		printf("%c ",p->data);
		putchar(10);
		printf("逆向遍历 Doublelink= ");
		while(p)
		{
			printf("%c ",p->data);
			p=p->last;
		}
		putchar(10);
	}
		return;
}

2.2.4 双链表的头删

cpp 复制代码
// 双向链表的头删
Doublelink delete_head(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==NULL)
	{
		free(head);
		head=NULL;
		return head;
	}
	// 2.链表有多个节点
	head=head->next;  // 让第二个节点成为头结点
	free(head->last);  // 释放原头结点
	head->last=NULL;  // 让新头结点的last指向空
}

2.2.5 双链表的尾插

cpp 复制代码
// 双向列表的尾插
Doublelink insert_tail(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s; // 直接让head指向新节点,即让新节点成为头结点
		return head;
	}
	// 2.链接有一个或多个节点
	Doublelink p=head;
	while(p->next!=NULL)  // 找到最后一个节点
	{
		p=p->next;
	}
	p->next=s;  // 让位后一个节点指向新节点,即新节点成为尾节点
	s->last=p;  // 让新节点的last指向原尾节点
	return head;

}

2.2.6 双链表的尾删

cpp 复制代码
// 双向列表的尾删
Doublelink delete_tail(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==NULL)
	{
		free(head);  // 释放头结点
		head=NULL;  // head指向空
		return head;
	}
	// 3.链表有多个节点
	else
	{
		Doublelink p=head;
		while(p->next->next!=NULL)  // 找到倒数第二个节点
		{
			p=p->next;
		}
		free(p->next);  // 释放最后一个节点
		p->next=NULL;  // 让原倒数第二个节点指向空,即成为最后一个节点
		return head;
	}
	
}

2.3 双链表所有程序

2.3.1 head.h

cpp 复制代码
#ifndef __HEAD_H__
#define __HEAD_H__


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum passble{SUCCESS,FALSE=-1};
typedef char datatype;
// 双向链表节点结构体
typedef struct Node
{
	//数据域:数据元素
	datatype data;
	//指针域:下一个节点的地址
	struct Node *next;
	//指针域:上一个节点的地址
	struct Node *last;
}*Doublelink;
Doublelink creat_link();
Doublelink insert_head(Doublelink head,datatype element);
void outlink(Doublelink head);
Doublelink delete_head(Doublelink head);
Doublelink insert_tail(Doublelink head,datatype element);
Doublelink delete_tail(Doublelink head);

#endif

2.3.2 main.c

cpp 复制代码
#include "head.h"
int main(int argc, const char *argv[])
{
	Doublelink head=NULL;  // 定义一个链表节点指针
	int n;
	printf("请输入存入数据数量n:");
	scanf("%d",&n);
	datatype element;
	for(int i=1;i<=n;i++)
	{
		printf("请输入第%d个元素:",i);
		// scanf("%c",&element);
		getchar();
		element=getchar();
		head=insert_head(head,element);
	}
// 双向列表的遍历
	outlink(head);
	
// 双向链表的头删
	head=delete_head(head);
	printf("头删后\n");
	outlink(head);

// 双向列表的尾插
	printf("请输入尾插元素个数:");
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		printf("请输入尾插的第%d个元素:",i);
		getchar();
		element=getchar();
		head=insert_tail(head,element);
	}
	outlink(head);

// 双向列表的尾删
	head=delete_tail(head);
	printf("尾删后\n");
	outlink(head);

	return 0;
}

2.3.3 fun.c

cpp 复制代码
#include "head.h"
// 创建节点
Doublelink creat_link()
{
	Doublelink s=(Doublelink)malloc(sizeof(struct Node));
	if(NULL==s)
		return NULL;
	s->data=0;  // 新节点的数据域初始化
	s->next=NULL;  // 新节点的指针域初始化
	s->last=NULL;
	return s;
}

// 双向列表的头插
Doublelink insert_head(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s;
		return head;
	}
	// 2.链表不为空,存在多个节点
	s->next=head;  // 新节点的next指向头节点
	head->last=s;  // 头结点的last指向新节点
	head=s; // 使新节点成为头结点
	return head;
}

// 双向列表的遍历
void outlink(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return;
	// 2.链表不为空
	else
	{
		Doublelink p=head;
		printf("正向遍历 Doublelink= ");
		while(p->next!=NULL)
		{
			printf("%c ",p->data);
			p=p->next;
		}
		printf("%c ",p->data);
		putchar(10);
		printf("逆向遍历 Doublelink= ");
		while(p)
		{
			printf("%c ",p->data);
			p=p->last;
		}
		putchar(10);
	}
		return;
}

// 双向链表的头删
Doublelink delete_head(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==NULL)
	{
		free(head);
		head=NULL;
		return head;
	}
	// 2.链表有多个节点
	head=head->next;  // 让第二个节点成为头结点
	free(head->last);  // 释放原头结点
	head->last=NULL;  // 让新头结点的last指向空
}

// 双向列表的尾插
Doublelink insert_tail(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s; // 直接让head指向新节点,即让新节点成为头结点
		return head;
	}
	// 2.链接有一个或多个节点
	Doublelink p=head;
	while(p->next!=NULL)  // 找到最后一个节点
	{
		p=p->next;
	}
	p->next=s;  // 让位后一个节点指向新节点,即新节点成为尾节点
	s->last=p;  // 让新节点的last指向原尾节点
	return head;

}

// 双向列表的尾删
Doublelink delete_tail(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==NULL)
	{
		free(head);  // 释放头结点
		head=NULL;  // head指向空
		return head;
	}
	// 3.链表有多个节点
	else
	{
		Doublelink p=head;
		while(p->next->next!=NULL)  // 找到倒数第二个节点
		{
			p=p->next;
		}
		free(p->next);  // 释放最后一个节点
		p->next=NULL;  // 让原倒数第二个节点指向空,即成为最后一个节点
		return head;
	}
	
}

2.4 输出效果

三、双向循环列表

3.1 双向循环链表的概念

双向循环链表:尾节点的下一个节点是头节点,头节点的上一个节点是尾节点

3.2 双向循环链表的操作

3.2.1 双向循环链表的创建

cpp 复制代码
#include "head.h"
// 创建节点
Doublelink creat_link()
{
	Doublelink s=(Doublelink)malloc(sizeof(struct Node));
	if(NULL==s)
		return NULL;
	s->data=0;  // 新节点的数据域初始化
	s->next=s;  // 新节点的指针域初始化
	s->last=s;
	return s;
}

3.2.2 双向循环链表的头插

cpp 复制代码
// 双向循环列表的头插
Doublelink insert_head(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s;
		return head;
	}
	// 2.链表不为空,存在多个节点
	s->next=head;  // 新节点的next指向头节点
	s->last=head->last;  // 新节点的last指向尾节点
	head->last->next=s;  // 尾节点的next指向新节点
	head->last=s;  // 头结点的last指向新节点
	head=s; // 使新节点成为头结点
	return head;
}

3.2.3 双向循环链表的遍历

cpp 复制代码
// 双向循环列表的遍历
void outlink(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return;
	// 2.链表不为空
	else
	{
		Doublelink p=head;
		printf("正向遍历 Doublelink= ");
		while(p->next!=head)
		{
			printf("%c ",p->data);
			p=p->next;
		}
		printf("%c ",p->data);
		putchar(10);
		printf("逆向遍历 Doublelink= ");
		while(p!=head)
		{
			printf("%c ",p->data);
			p=p->last;
		}
		printf("%c",p->data);
		putchar(10);
	}
		return;
}

3.2.4 双向循环链表的头删

cpp 复制代码
// 双向循环链表的头删
Doublelink delete_head(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==head)
	{
		free(head);
		head=NULL;
		return head;
	}
	// 2.链表有多个节点
	Doublelink p=head;
	head->last->next=head->next;
	head=head->next;  // 让第二个节点成为头结点
	head->last=head->last->last;  // 让新头结点指向尾节点
	free(p);  // 释放原头结点
	p=NULL;  // 让指针p指向空
	return head;
}

3.2.5 双向循环链表的尾插

cpp 复制代码
// 双向循环列表的尾插
Doublelink insert_tail(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s; // 直接让head指向新节点,即让新节点成为头结点
		return head;
	}
	// 2.链接有一个或多个节点
	
	head->last->next=s;  // 让最后一个节点指向新节点,即新节点成为尾节点
	s->next=head;
	s->last=head->last;  // 让新节点的last指向原尾节点
	head->last=s;
	return head;

}

3.2.6 双向循环链表的尾删

cpp 复制代码
// 双向循环列表的尾删
Doublelink delete_tail(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==head)
	{
		free(head);  // 释放头结点
		head=NULL;  // head指向空
		return head;
	}
	// 3.链表有多个节点
	else
	{
		head->last=head->last->last;  // 让头结点的last指向倒数第二个节点
		free(head->last->next);  // 释放最后一个节点
		head->last->next=head;  // 让原倒数第二个节点指向头结点,即成为最后一个节点
		return head;
	}
	
}

3.3 双向循环链表所有程序

3.3.1 head.h

cpp 复制代码
#ifndef __HEAD_H__
#define __HEAD_H__


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum passble{SUCCESS,FALSE=-1};
typedef char datatype;
// 双向链表节点结构体
typedef struct Node
{
	//数据域:数据元素
	datatype data;
	//指针域:下一个节点的地址
	struct Node *next;
	//指针域:上一个节点的地址
	struct Node *last;
}*Doublelink;
Doublelink creat_link();
Doublelink insert_head(Doublelink head,datatype element);
void outlink(Doublelink head);
Doublelink delete_head(Doublelink head);
Doublelink insert_tail(Doublelink head,datatype element);
Doublelink delete_tail(Doublelink head);

#endif

3.3.2 main.c

cpp 复制代码
#include "head.h"
int main(int argc, const char *argv[])
{
	Doublelink head=NULL;  // 定义一个链表节点指针
	int n;
	printf("请输入存入数据数量n:");
	scanf("%d",&n);
	datatype element;
	for(int i=1;i<=n;i++)
	{
		printf("请输入第%d个元素:",i);
		// scanf("%c",&element);
		getchar();
		element=getchar();
		head=insert_head(head,element);
	}
// 双向循环列表的遍历
	outlink(head);

// 双向循环链表的头删
	head=delete_head(head);
	printf("头删后\n");
	outlink(head);

// 双向循环列表的尾插
	printf("请输入尾插元素个数:");
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		printf("请输入尾插的第%d个元素:",i);
		getchar();
		element=getchar();
		head=insert_tail(head,element);
	}
	outlink(head);

// 双向循环列表的尾删
	head=delete_tail(head);
	printf("尾删后\n");
	outlink(head);
	return 0;
}

3.3.3 fun.c

cpp 复制代码
#include "head.h"
// 创建节点
Doublelink creat_link()
{
	Doublelink s=(Doublelink)malloc(sizeof(struct Node));
	if(NULL==s)
		return NULL;
	s->data=0;  // 新节点的数据域初始化
	s->next=s;  // 新节点的指针域初始化
	s->last=s;
	return s;
}

// 双向循环列表的头插
Doublelink insert_head(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s;
		return head;
	}
	// 2.链表不为空,存在多个节点
	s->next=head;  // 新节点的next指向头节点
	s->last=head->last;  // 新节点的last指向尾节点
	head->last->next=s;  // 尾节点的next指向新节点
	head->last=s;  // 头结点的last指向新节点
	head=s; // 使新节点成为头结点
	return head;
}

// 双向循环列表的遍历
void outlink(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return;
	// 2.链表不为空
	else
	{
		Doublelink p=head;
		printf("正向遍历 Doublelink= ");
		while(p->next!=head)
		{
			printf("%c ",p->data);
			p=p->next;
		}
		printf("%c ",p->data);
		putchar(10);
		printf("逆向遍历 Doublelink= ");
		while(p!=head)
		{
			printf("%c ",p->data);
			p=p->last;
		}
		printf("%c",p->data);
		putchar(10);
	}
		return;
}

// 双向循环链表的头删
Doublelink delete_head(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==head)
	{
		free(head);
		head=NULL;
		return head;
	}
	// 2.链表有多个节点
	Doublelink p=head;
	head->last->next=head->next;
	head=head->next;  // 让第二个节点成为头结点
	head->last=head->last->last;  // 让新头结点指向尾节点
	free(p);  // 释放原头结点
	p=NULL;  // 让指针p指向空
	return head;
}

// 双向循环列表的尾插
Doublelink insert_tail(Doublelink head,datatype element)
{
	Doublelink s=creat_link();
	s->data=element;
	// 1.判断链表是否为空
	if(NULL==head)
	{
		head=s; // 直接让head指向新节点,即让新节点成为头结点
		return head;
	}
	// 2.链接有一个或多个节点
	
	head->last->next=s;  // 让最后一个节点指向新节点,即新节点成为尾节点
	s->next=head;
	s->last=head->last;  // 让新节点的last指向原尾节点
	head->last=s;
	return head;

}

// 双向循环列表的尾删
Doublelink delete_tail(Doublelink head)
{
	// 1.判断链表是否为空
	if(NULL==head)
		return head;
	// 2.判断链表节点是否为1
	else if(head->next==head)
	{
		free(head);  // 释放头结点
		head=NULL;  // head指向空
		return head;
	}
	// 3.链表有多个节点
	else
	{
		head->last=head->last->last;  // 让头结点的last指向倒数第二个节点
		free(head->last->next);  // 释放最后一个节点
		head->last->next=head;  // 让原倒数第二个节点指向头结点,即成为最后一个节点
		return head;
	}
	
}

3.4 输出效果

相关推荐
CS创新实验室13 分钟前
计算机考研之数据结构:大 O 记号
数据结构·考研
wen__xvn1 小时前
每日一题洛谷P1914 小书童——凯撒密码c++
数据结构·c++·算法
BUG 劝退师2 小时前
八大经典排序算法
数据结构·算法·排序算法
小小小白的编程日记3 小时前
List的基本功能(1)
数据结构·c++·算法·stl·list
_Itachi__3 小时前
LeetCode 热题 100 283. 移动零
数据结构·算法·leetcode
柃歌3 小时前
【UCB CS 61B SP24】Lecture 5 - Lists 3: DLLists and Arrays学习笔记
java·数据结构·笔记·学习·算法
商bol453 小时前
复习dddddddd
数据结构·c++·算法
干炒 牛河7 小时前
数据结构:哈希表(unordered_map)
数据结构·算法·散列表
非 白9 小时前
数据结构——树
数据结构·笔记·考研
Dizzy.51711 小时前
数据结构(查找)
数据结构·学习·算法