1. 循环链表定义
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表成为单循环链表,简称循环链表。
(注:这里并不是说循环链表一定要有头结点。但是对于空链表,则需要有头结点表示该存储方式为一个链表,且“head->next == head”)
2. 循环链表操作
1)初始化循环链表:见例1.
//例1
Status ds_init(Node **node)
{
*node = (Node *)malloc(sizeof(Node));
(*node)->Next = *node;
}
2)插入元素:见例2.
//例2
Status ds_insert(Node **node, int i, Elemtype n)
{
Node *target, *temp,*p;
int j;
target = *node;
temp = (Node *)malloc(sizeof(Node));
temp->Data = n;
if(i == 1)
{
while(target && target->Next != *node)
{
target = target->Next;
}
temp->Next = *node;
target->Next = temp;
*node = temp;
}
else
{
for(j = 1; j < i-1; j++)
{
target = target->Next;
}
temp->Next = target->Next;
target->Next = temp;
}
}
3)删除元素:例3
//例3
Status ds_delete(Node **node, int i)
{
Node *target, *temp;
int j;
target = *node;
if(i == 1)
{
for(; target->Next != *node; target = target->Next)
;
printf("123\n");
temp = *node;
target->Next = (*node)->Next;
*node = target->Next;
}
else
{
for(j = 1; j < i-1; j++)
{
target = target->Next;
}
if(target->Next == *node)
{
temp = *node;
target->Next = (*node)->Next;
*node = target->Next;
}
else
{
temp = target->Next;
target->Next = temp->Next;
}
}
printf("The delete data is: %d\n", temp->Data);
}
//例4,总体框架代码
#include<stdio.h>
#include<stdlib.h>
typedef int Elemtype;
typedef int Status;
typedef struct LinkList
{
Elemtype Data;
struct LinkList *Next;
}Node;
Status vist(Node *node)
{
printf("%d ", (node)->Data);
}
Status travellist(Node *node)
{
Node *temp;
temp = node;
vist(temp);
temp = (node)->Next;
while(temp && temp != node)
{
vist(temp);
temp = temp->Next;
}
printf("\n");
}
Status ds_init(Node **node)
{
*node = (Node *)malloc(sizeof(Node));
(*node)->Next = *node;
}
Status ds_creatlinklist(Node **node)
{
int data;
Node *Target, *temp;
printf("Please input the node data: ");
scanf("%d", &data);
(*node)->Data = data;
printf("If you input 0, the process of creating linklist will be stopped!\n");
while(1)
{
printf("Please input the node data: ");
scanf("%d", &data);
if(data == 0)
{
break;
}
for(Target = (*node); Target->Next != (*node); Target = Target->Next )
;
temp = (Node *)malloc(sizeof(Node));
temp->Data = data;
temp->Next = *node;
Target->Next = temp;
}
}
Status ds_insert(Node **node, int i, Elemtype n)
{
Node *target, *temp,*p;
int j;
target = *node;
temp = (Node *)malloc(sizeof(Node));
temp->Data = n;
if(i == 1)
{
while(target && target->Next != *node)
{
target = target->Next;
}
temp->Next = *node;
target->Next = temp;
*node = temp;
}
else
{
for(j = 1; j < i-1; j++)
{
target = target->Next;
}
temp->Next = target->Next;
target->Next = temp;
}
}
Status ds_delete(Node **node, int i)
{
Node *target, *temp;
int j;
target = *node;
if(i == 1)
{
for(; target->Next != *node; target = target->Next)
;
printf("123\n");
temp = *node;
target->Next = (*node)->Next;
*node = target->Next;
}
else
{
for(j = 1; j < i-1; j++)
{
target = target->Next;
}
if(target->Next == *node)
{
temp = *node;
target->Next = (*node)->Next;
*node = target->Next;
}
else
{
temp = target->Next;
target->Next = temp->Next;
}
}
printf("The delete data is: %d\n", temp->Data);
}
Status ds_length(Node **node)
{
int i;
Node *target;
target = *node;
for(i = 1; target->Next != *node; target->Next)
{
target = target-> Next;
i++;
}
printf("The length is: %d\n", i);
return i;
}
Status ds_treble(Node **node)
{
Node *target, *temp;
int i;
target = *node;
for(i = 1; i < 2; i++)
{
target = target->Next;
}
temp = target->Next;
target->Next = temp->Next;
*node = temp->Next;
}
void main()
{
Node *node;
int len = 0;
int num, pos;
char operation;
ds_init(&node);
printf("1.初始化链表 \n\n2.插入结点 \n\n3.删除结点 \n\n#.退出 \n\n请选择你的操作:");
while(operation != '#')
{
scanf("%c", &operation);
switch(operation)
{
case '1':
ds_creatlinklist(&node);
travellist(node);
printf("\n");
break;
case '2':
printf("Please input the number that you want insert:");
scanf("%d", &num);
printf("Please input the postion that you want insert:");
scanf("%d", &pos);
ds_insert(&node, pos, num);
travellist(node);
printf("\n");
break;
case '3':
printf("Please input the number that you want delete:");
scanf("%d", &num);
ds_delete(&node, num);
travellist(node);
printf("\n");
break;
}
}
}
3. Josephus问题:
在罗马人占领乔塔帕特后, 39 个犹太人与Josephus 及他的朋友躲到一个洞中, 39 个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式, 41 个人排成一个圆圈,由第 1 个人开始报数,每报数到第 3 人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而 Josephus和他的朋友并不想遵从, Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16 个与第 31 个位置,于是逃过了这场死亡游戏。见例5.
//例5
#include<stdio.h>
#include<stdlib.h>
typedef int Elemtype;
typedef int Status;
typedef struct LinkList
{
Elemtype Data;
struct LinkList *Next;
}Node;
Status vist(Node *node)
{
printf("%d ", (node)->Data);
}
Status travellist(Node *node)
{
Node *temp;
temp = node;
vist(temp);
temp = (node)->Next;
while(temp && temp != node)
{
vist(temp);
//printf("$$$$$$$$$$");
temp = temp->Next;
}
printf("\n");
}
Status ds_init(Node **node)
{
*node = (Node *)malloc(sizeof(Node));
(*node)->Next = *node;
}
Status ds_creatlinklist(Node **node)
{
int data = 1;
Node *Target, *temp;
(*node)->Data = data;
for(data = 2; data <42; data++)
{
for(Target = (*node); Target->Next != (*node); Target = Target->Next )
;
temp = (Node *)malloc(sizeof(Node));
temp->Data = data;
temp->Next = *node;
Target->Next = temp;
}
}
Status ds_length(Node **node)
{
int i;
Node *target;
target = *node;
for(i = 1; target->Next != *node; target->Next)
{
target = target-> Next;
i++;
}
return i;
}
Status ds_josephus(Node **node)
{
Node *target, *temp;
int i;
target = *node;
for(i = 1; i < 2; i++)
{
target = target->Next;
}
temp = target->Next;
target->Next = temp->Next;
*node = temp->Next;
}
void main()
{
Node *node;
int len = 0;
ds_init(&node);
ds_creatlinklist(&node);
travellist(node);
printf("\n");
len = ds_length(&node);
while(len > 2)
{
ds_josephus(&node);
len = ds_length(&node);
}
travellist(node);
}
//输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
16 31
4. 两个循环链表连接问题
//例6
#include<stdio.h>
#include<stdlib.h>
typedef int Elemtype;
typedef void Status;
typedef struct node
{
Elemtype data;
struct node *next;
}Node;
Status InitCirLinkList(Node **head)
{
*head = (Node *)malloc(sizeof(Node));
(*head)->next = (*head);
}
Status CreateLinkListTail(Node **head, int n)
{
Node *target, *temp;
int i;
target = *head;
target->data = 1;
for(i = 2; i <= n; i++)
{
temp = (Node *)malloc(sizeof(Node));
temp->data = i;
target->next = temp;
target = target->next;
}
target->next = (*head);
}
Status CreateLinkListhead(Node **head, int n)
{
Node *target, *rear, *temp;
int i;
rear = *head;
target = *head;
target->data = 1;
for(i = 1; i <= n; i++)
{
temp = (Node *)malloc(sizeof(Node));
temp->data = i;
temp->next = target;
target = temp;
}
rear->next = target;
(*head) = target;
}
Status Visit(Node *node)
{
if(node)
{
printf("%d ", node->data);
}
printf("\n");
}
Status Traversal(Node **head)
{
Node *target;
target = *head;
Visit(target);
target = target->next;
while(target && target != *head)
{
Visit(target);
target = target->next;
}
}
Status Connect(Node **head1, Node **head2)
{
Node *target1, *target2;
target1 = *head1;
target2 = *head2;
while(target1 && target1->next != *head1)
{
target1 = target1->next;
}
target1->next = target2;
while(target2 && target2->next != *head2)
{
target2 = target2->next;
}
target2->next = *head1;
}
void main()
{
Node *L1;
Node *L2;
int n1, n2;
char c;
InitCirLinkList(&L1);
InitCirLinkList(&L2);
printf("How many element that you want create for the first LinkList?");
scanf("%d", &n1);
CreateLinkListTail(&L1, n1);
Traversal(&L1);
printf("\n");
printf("How many element that you want create for the second LinkList?");
scanf("%d", &n2);
CreateLinkListhead(&L2, n2);
Traversal(&L2);
printf("\n");
Connect(&L1, &L2);
Traversal(&L1);
}
5. 判断链表内部是否有环(例题设置链表为非循环链表)
方法1:利用快慢指针来判定,快慢指针同时遍历链表,快指针的速度是慢指针的速度的2倍。如果,到后面快指针追上慢指针说明有环。见例7.
//例7
Status Fspointer(Node **L) //利用快慢指针来统计
{
Node *fast, *slow;
int step = 0;
fast = *L;
slow = *L;
while(fast != NULL && slow != NULL && fast->next != NULL) /*“fast->next != NULL”是因为fast要跳2格,因此中间不能为空,如果为空则结束*/
{
fast = fast->next->next;
slow = slow->next;
step++;
if(fast == slow)
{
printf("There has loop in this linklist!");
return;
}
}
printf("There is no loop in this linklist!");
}
方法2:利用计步器step1和step2,step1永远是一直一步步往下走,step2是:当step2的node和step1的node完全相同时,判定step2是不是等于step1,如果相等,则step1++,step2归零,然后继续执行,直到step1走完链表;或者当step2的node等于step1的node,但是step2 != step1,则说明有环。见例8.
//例8
Status Comparestep(Node **L) //通过设置两个计步器来比较同一点的步数是否相同
{
int step1, step2;
Node *p, *q;
p = *L;
step1 = 0;
while(p)
{
q = *L;
step2 = 0;
while(q)
{
if(p == q)
{
if(step1 == step2)
{
break;
}
else
{
printf("From the %dth the loop is beginning!", step2);
return;
}
}
q = q->next;
step2++;
}
p = p->next;
step1++;
}
printf("There is no loop in this linklist!");
}
//例9,总体框架代码
#include<stdio.h>
#include<stdlib.h>
typedef int Elemtype;
typedef void Status;
//#define LINKLIST_SIZE 15;
typedef struct node
{
Elemtype data;
struct node *next;
}Node;
Status vist(Node *node)
{
printf("%d ", (node)->data);
}
Status TravelList(Node *node)
{
Node *temp;
temp = node;
vist(temp);
temp = (node)->next;
while(temp && temp != node)
{
vist(temp);
temp = temp->next;
}
printf("\n");
}
Status InitLinkList(Node **L)
{
(*L) = (Node *)malloc(sizeof(Node));
(*L)->next = NULL;
}
Status CrearteLinkListTail(Node **L) //尾插法。创建有环单链表
{
Node *target, *temp;
int i;
target = *L;
target->data = rand()%100+1;
for(i = 2; i <= 15; i++)
{
temp = (Node *)malloc(sizeof(Node));
temp->data = rand()%100+1;
target->next = temp;
target = target->next;
}
target->next = (*L)->next->next->next;
}
Status CreateLinkListHead(Node **L) //头插法,创建无环单链表
{
Node *target, *temp;
int i;
target = *L;
target->data = rand()%100+1;
for(i = 2; i <= 15; i++)
{
temp = (Node *)malloc(sizeof(Node));
temp->data = rand()%100+1;
temp->next = target;
target = temp;
}
*L = target;
}
Status Comparestep(Node **L) //通过设置两个计步器来比较同一点的步数是否相同
{
int step1, step2;
Node *p, *q;
p = *L;
step1 = 0;
while(p)
{
q = *L;
step2 = 0;
while(q)
{
if(p == q)
{
if(step1 == step2)
{
break;
}
else
{
printf("From the %dth the loop is beginning!", step2);
return;
}
}
q = q->next;
step2++;
}
p = p->next;
step1++;
}
printf("There is no loop in this linklist!");
}
Status Fspointer(Node **L) //利用快慢指针来统计
{
Node *fast, *slow;
int step = 0;
fast = *L;
slow = *L;
while(fast != NULL && slow != NULL && fast->next != NULL) //“fast->next != NULL”是因为fast要跳2格,因此中间不能为空,如果为空则结束
{
fast = fast->next->next;
slow = slow->next;
step++;
if(fast == slow)
{
printf("There has loop in this linklist!");
return;
}
}
printf("There is no loop in this linklist!");
}
Status ClearLinkList(Node **L)
{
Node *target, *temp;
target = *L;
while(target)
{
temp = target;
target = target->next;
free(temp);
}
}
void main()
{
Node *L;
char operation;
InitLinkList(&L);
printf("\n1.创建有环链表(尾插法) \n2.创建无环链表(头插法) \n3.判断链表是否有环 \n#.退出 \n\n请选择你的操作:\n");
while(operation != '#')
{
scanf("%c", &operation);
switch(operation)
{
case '1':
CrearteLinkListTail(&L);
printf("\n");
break;
case '2':
CreateLinkListHead(&L);
printf("\n");
break;
case '3':
printf("Method one! ");
Comparestep(&L);
printf("\n");
printf("Method two! ");
Fspointer(&L);
printf("\n");
break;
case '#':
exit(0);
}
}
}
5. 拉丁方阵
拉丁方阵是一种 n×n 的方阵,方阵中恰有 n 种不同的元素,每种元素恰有 n 个,并且每种元素在一行和一列中 恰好出现一次。见例10.
//例10,核心代码
Status TraversalList(Node **node)
{
Node *target;
target = *node;
Visit(target);
target = target->next;
while(target != *node)
{
Visit(target);
target = target->next;
}
}