数据结构之双向循环链表

双向循环链表:就是在双向链表的基础之上把头节点和尾结点也用两个指针相互链接,形成一个环:
在这里插入图片描述
结构我们懂了那么接下来开始我们的准备工作

#include<stdio.h>
#include<stdlib.h>
struct node {
	int data;
	struct node* left;
	struct node* right;
};
struct list {
	int size;
	struct node* headnode;
	struct node* tailnode;
};
struct node* createnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->data = data;
	newnode->left = NULL;
	newnode->right = NULL;
	return newnode;
}
struct list* createlist() {
	struct list* newlist = (struct list*)malloc(sizeof(struct list));
	newlist->size = 0;
	newlist->headnode = newlist->tailnode=NULL;
	return newlist;
}
bool isempty(struct list* plist) {
	return plist->size == 0;
}
int sizeoflist(struct list* plist) {
	return plist->size;
}

在头部插入节点:

void insertbyhead(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (isempty(plist)) {
		plist->headnode = plist->tailnode = newnode;
		plist->headnode->left = plist->tailnode;
		plist->tailnode->right = plist->headnode;
	}
	else {
		newnode->right = plist->headnode;
		plist->headnode->left = newnode;
		newnode->left = plist->tailnode;
		plist->tailnode->right = newnode;
		plist->headnode = newnode;
	}
	plist->size++;
}

关于只有一个点的情况,下图所示:
在这里插入图片描述
其他情况如下:在这里插入图片描述
好,这就是头结点插入,尾结点插入也是一样的:正好对称过来:

void insertbytail(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (isempty(plist)) {
		plist->headnode = plist->tailnode = newnode;
		plist->headnode->left = plist->tailnode;
		plist->tailnode->right = plist->headnode;
	}
	else {
		plist->headnode->left = newnode;
		newnode->left = plist->tailnode;
		plist->tailnode->right = newnode;
		newnode->right = plist->headnode;
		plist->tailnode = newnode;
	}
	plist->size++;
}

接下来是寻找节点插入:
跟上一次我写的双向链表是一样的:

void insertbyself(struct list* plist, int data,int posdata) {
	struct node* newnode = createnode(data);
	if (isempty(plist)) {
		printf("无法插入");
	}
	else if (plist->headnode->data == posdata) {
		insertbyhead(plist, data);
		plist->size++;
	}
	else if (plist->size != 1) {
		struct node* posfro = plist->headnode;
		struct node* pos = plist->headnode->right;
		while (pos != plist->headnode && pos->data != posdata) {
			posfro = pos;
			pos = pos->right;
		}
		if (pos == plist->headnode) {
			printf("找不到插入的地方");
		}
		else {
			posfro->right = newnode;
			newnode->left = posfro;
			pos->left = newnode;
			newnode->right = pos;
			plist->size++;
		}
	}
}

接下来是删除:头结点删除:
在这里插入图片描述
知道了原理,源代码如下:

void deletebyhead(struct list* plist) {
	if (isempty(plist)) {
		printf("NULL\n");
	}
	else {
		struct node* deletenode = plist->headnode;
		deletenode->right->left = plist->tailnode;
		plist->tailnode->right = deletenode->right;
		plist->headnode = plist->headnode->right;
		free(deletenode);
		plist->size--;
	}
}

尾结点删除还是就是反过来而已:

void deletebytail(struct list* plist) {
	if (isempty(plist)) {
		printf("NULL\n");
	}
	else {
		struct node* deletenode = plist->tailnode;
		deletenode->left->right = plist->headnode;
		plist->headnode->left = deletenode->left;
		plist->tailnode = plist->tailnode->left;
		free(deletenode);
		plist->size--;
	}
}

接下来是删除:
在这里插入图片描述
跟上面的添加一样,如果要找的点恰巧是头结点,就单独列出来,也是跟双向链表一样的:

void deletebyself(struct list* plist, int posdata) {
	if (isempty(plist)) {
		printf("NULL\n");
	}
	else if (plist->headnode->data == posdata) {
		deletebyhead(plist);
		plist->size--;
	}
	else {
		struct node* posfro = plist->headnode;
		struct node* pos = plist->headnode->right;
		while (pos != plist->headnode && pos->data != posdata) {
			posfro = pos;
			pos = pos->right;
		}
		if (pos == plist->headnode) {
			printf("找不到删除的元素");
		}
		else {
			posfro->right = pos->right;
			pos->right->left = posfro;
			free(pos);
			plist->size--;
		}
	}
}

在这里我想说一下遍历链表,因为遍历完之后不是NULL 所以用之前的NULL一定是不行了,但是循环完毕肯定是回到了头结点,咱们只需要查看是不是返回到头结点了就行,所以,下面的打印程序也就有了:

void printlistright(struct list* plist) {
	if (isempty(plist)) {
		printf("NULL\n");
	}
	else {
		struct node* pmove = plist->headnode;
		printf("%d\t", pmove->data);
		pmove = pmove->right;
		while (pmove != plist->headnode) {
			printf("%d\t", pmove->data);
			pmove = pmove->right;
		}
		printf("\n");
	}
}

这个是向右打印,向左打印,判断是否回到尾结点就行:

void printlistleft(struct list* plist) {
	if (isempty(plist)) {
		printf("NULL\n");
	}
	else {
		struct node* pmove = plist->tailnode;
		printf("%d\t", pmove->data);
		pmove = pmove->left;
		while (pmove != plist->tailnode) {
			printf("%d\t", pmove->data);
			pmove = pmove->left;
		}
		printf("\n");
	}
}

好了,双向循环链表就到这儿了,这个结构用于一个圈圈轮换的游戏是非常适合的,一种游戏是一个人开始数数,数到指定的数停止,然后遍历到的这个人就出局,我也忘了叫什么游戏了,就类似这样的游戏,或者题目就可以用这个。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值