双向循环链表:就是在双向链表的基础之上把头节点和尾结点也用两个指针相互链接,形成一个环:
结构我们懂了那么接下来开始我们的准备工作
:
#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");
}
}
好了,双向循环链表就到这儿了,这个结构用于一个圈圈轮换的游戏是非常适合的,一种游戏是一个人开始数数,数到指定的数停止,然后遍历到的这个人就出局,我也忘了叫什么游戏了,就类似这样的游戏,或者题目就可以用这个。