一
循环链表是另一种形式的链式存储结构,他的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环,由此从表中任一结点出发均可找到表中其他结点,其操作与单链表基本一致,差别在于循环条件不是p或p->next是否为空,而是否等于头指针。
二
循环链表的结点定义,与单链表一样,在生成循环链表是应该,将r->next == head(即最后一个结点指针域指向头结点)
typedef struct node
{
int data;
struct node *next;
}sqlist, *linkList;
三
拉丁方阵:
#include "stdio.h"
#include "stdlib.h"
#define OK 1
#define ERROR 0
typedef int Status;
typedef struct node
{
int data;
struct node *next;
} *linkList, sqlist;
//输出数据
Status visit(int e)
{
printf("%d ", e);
return OK;
}
//输出整个链表
Status ListTraverse(linkList L)
{
linkList p = L;
while(1)
{
visit(p->data);
p = p->next;
if(p == L)
{
return OK;
}
}
}
//初始化循环链表
Status InitList(linkList *L)
{
*L = (linkList)malloc(sizeof(sqlist));
if(!(*L))
{
return ERROR;
}
(*L)->next = *L;
//printf("初始化%d %d", *L, (*L)->next);
return OK;
}
//生成循环链表
Status CreateList(linkList *L, int i)
{
linkList p, r;
int k=1;
*L = (linkList)malloc(sizeof(sqlist));
(*L)->next = NULL;
r = *L;
(*L)->data = k;
//printf("(*L)元素值:%d", (*L)->data);
for(k=2; k<=i; k++)
{
p=(linkList)malloc(sizeof(sqlist));
p->data = k;
//printf("元素值:%d", p->data);
r->next = p;
r = p;
}
p->next = *L;
return OK;
}
//循环链表长度
int ListLength(linkList L)
{
linkList p = L;
int i=0;
while(1)
{
p = p->next;
i ++;
if(p==L)
return i;
}
}
//拉丁方阵输出
Status LatinOut(linkList L)
{
int i = ListLength(L);
int j;
linkList p, r;
p = L;
for(j=0; j<i; j++)
{
ListTraverse(p);
printf("\n");
r = p->next;
p = r;//交换p与r的位置,使p->next成为新链表的起点
}
return OK;
}
int main(void)
{
linkList L;
int i;
InitList(&L);
printf("\n请输入数字(1-9):");
scanf("%d", &i);
CreateList(&L, i);
printf("按如下排列:\n");
ListTraverse(L);
printf("\n\n");
printf("拉丁方阵:\n");
LatinOut(L);
return 0;
}
魔术师发牌:魔术师利用已排好顺序的13张黑桃牌,第一张翻开黑桃A,放到桌子上,然后继续,数1,2将第一张放到牌的底部,第二张刚好是黑桃2,放到桌面,然后以此将所有牌翻出。所以魔术师的牌顺序如何放置呢?
#define CardNumber 13
//创建循环链表
linkList CreateLinkList()
{
linkList head = NULL;
linkList s, r;
int i;
r = head;
for(i=1; i<=CardNumber; i++)
{
s = (linkList)malloc(sizeof(sqlist));
s->data = 0;
if(head == NULL)
head = s;
else
r->next = s;
r = s;
}
r->next = head;
return head;
}
void Magician(linkList head)
{
linkList p;
int j;
int CountNumber = 2;
p = head;
p->data = 1; //第一张牌
while(1)
{
for(j=0; j<CountNumber; j++)
{
p = p->next;
if(p->data != 0)
{
p->next;
j--;
}
}
if(p->data == 0)
{
p->data = CountNumber;
CountNumber ++;
if(CountNumber == 14)
break;
}
}
}
void DestroyList(linkList *list)
{
linkList ptr = *list;
linkList buff[CardNumber];
int i = 0;
while(i < CardNumber)
{
buff[i++] = ptr;
ptr = ptr->next;
}
for(i=0; i<CardNumber; ++i)
free(buff[i]);
*list = 0;
}
int main(void)
{
linkList p;
int i;
p = CreateLinkList();
Magician(p);
printf("按如下排列:\n");
for(i=0; i<CardNumber; i++)
{
printf("黑桃%d ", p->data);
p = p->next;
}
DestroyList(&p);
return 0;
}
利用循环列表进行魔术师发牌,必须考虑一个很现实的问题,每翻出一张牌,要将其放到桌面,牌堆里就会少一张牌,而循环链表长度总为13,并且里面的元素不变。所以排顺序时要按照,事先已将翻出来的牌“剔除”,即:
if(p->data != 0) //访问到的结点已有元素,就“跳过”
{
p->next;
j--;
}