C语言链表作用域,C语言实现判断单链表中是否有环

/*

* @Author: xgh

* @Date: 2020-06-14 14:18:08

* @LastEditTime: 2020-06-14 22:39:38

* @LastEditors: Please set LastEditors

* @Description: 判断单链表中是否带环

* @FilePath: \VS-CODE-C\.vscode\loopSinglyLinkedLists\loopSilnglyLinkedLists.c

*/

#include "data.h"

Statue GreateListTail(LinkList *L, int n);

Statue GetLength(LinkList L);

void ListElemOutput(LinkList L);

Statue setLoopLinkList(LinkList L, int loop_pos);

int isLoopLinkList_01(LinkList L);

int isLoopLinkList_02(LinkList L);

int main(void){

LinkList list = NULL;

GreateListTail(&list, 6);

printf("表长度为:%d\n", GetLength(list));

ListElemOutput(list);

if(setLoopLinkList(list, 4)){

printf("快慢指针方式,环入口为第%d个结点\n\n", isLoopLinkList_01(list));

printf("记步数方式,环入口为第%d个结点\n\n", isLoopLinkList_02(list));

}

return 0;

}

/**

* @description: 输出表内容

* @param {LinkList L: 结构体一级指针}

* @return: NULL

*/

void ListElemOutput(LinkList L)

{

LinkList p = L->next;

printf("当前表数据为:");

while(p){

printf("%4d", p->data);

p = p->next;

}

printf("\n");

}

/**

* @description: 获取表长度

* @param {LinkList L:结构体指针}

* @return: 表长度

*/

Statue GetLength(LinkList L)

{

int length = 0; // 保存表长度变量

LinkList p = L->next; // 获取头结点的下一个结点地址

while (p != NULL) // 结点指针域不为NULL, 说明有数据

{

length++; // 长度加1

p = p->next; // 获取下一个结点地址

}

// 返回结果

return length;

}

/**

* @description: 尾插法创建链表, 数据域data存放随机数[1, 100]

* @param {LinkList *L:结构体二级指针}

* @param {int n: 插入数据的个数}

* @return: FAILUER: 内存分配失败

* @return: SUCCESS: 插入成功

*/

Statue GreateListTail(LinkList *L, int n)

{

LinkList r, s;

int i;

srand(time(0)); // 初始化随机数种子

//获取头指针

*L = (LinkList) malloc (sizeof(node));

if(*L == NULL){

printf("内存分配失败\n\n");

return FAILURE;

}

r = *L; // 将内存分配的头指针给到r

for(i = 0; i < n; i++){

s = (LinkList) malloc (sizeof(node)); // 新结点

s->data = rand() % 100 + 1; // rand()生成随机数, 对100取模, 生成[0, 99]的数, 加1生成[1, 100]

r->next = s; // r指向新结点

r = s; //将r移动到新结点, 即现在r为新结点

}

r->next = NULL; // 表尾

return SUCCESS;

}

/**

* @description: 设置带环的单链表

* @param {LinkList L:一级指针}

* @param {int loop_pos:构建环的位置}

* @return: ERROR: 数据错误

* @return:SUCCESS: 设置成功

*/

Statue setLoopLinkList(LinkList L, int loop_pos){

// 判断链表是否为空或者构建回环的位置是否正确

if(L == NULL || GetLength(L) == 0 || loop_pos >= GetLength(L)){

return ERROR;

}

// 头结点

LinkList node = L;

// 第loop_pos位置的结点

LinkList loop_node = NULL;

int i = 0;

// 循环判断, 到表尾退出

while(1){

// 判断是否到达表尾

if(node->next != NULL){

// 未到达表尾, 则结点后移

node = node->next;

i++; // 结点数加1

// 判断是否到达设置回环的结点

if(i == loop_pos){

// 获取该结点

loop_node = node;

}

}else{ // 到达表尾退出

break;

}

}

// 循环结束, 此时node为表尾结点, 将它的指针域指向回环的结点

node->next = loop_node;

printf("单链表回环设置成功\n\n");

return SUCCESS;

}

/**

* @description: 判断单链表是否是带环(快慢指针方式)

* @param {LinkList L: 一级指针}

* @return: 环的位置

* @return: ERROR: 数据错误或没有环

*/

int isLoopLinkList_01(LinkList L){

if(L == NULL || L->next == NULL){

printf("表错误\n\n");

return ERROR;

}

LinkList slow = L; // 慢指针

LinkList fast = L; // 快指针

int pos = 0; // 相遇标志

int loop_In = 0; // 到环入口的结点数

// 判断有没有环

while(fast != NULL && fast->next != NULL ){

fast = fast->next->next;

slow = slow->next;

// 快慢指针是相遇

if(fast == slow){

pos = 1;

break; // 跳出循环

}

}

// 在有环的基础上找到第一个入口

if(pos == 1){

fast = L; // 快指针从头开始走,且这次一次只后移一个结点

// 快慢指针是否相遇

while(fast != slow){

// 快慢指针后移一个结点

fast = fast->next;

slow = slow->next;

loop_In++;

}

printf("快慢指针的方式,环入口的结点数据为%d\n\n", slow->data);

return loop_In;

}

return ERROR;

}

/**

* @description: 判断单链表是否是带环(计算步数方式)

* @param {LinkList L: 一级指针}

* @return: 环的位置

* @return: ERROR: 数据错误或没有环

*/

int isLoopLinkList_02(LinkList L){

int count_01 = 0, count_02; // 计算两个指针的步数

LinkList p1 = L, p2;

while(p1)

{

count_02 = 0; // 每次指针p1后移一个结点, 指针p2都从新计数

p2 = L;

// 每次指针p2重新走一次, 走到指针p1的位置

while(p2 && (p1 != p2)){

p2 = p2->next;

count_02++;

}

// 判断是不是有环, 有环则是屏p1 == p2, 且步数不一样

if(p1 == p2 && (count_01 != count_02)){

printf("记步数的方式,环入口的结点数据为%d\n\n", p2->data);

return count_02;

}

// 指针p1往后移一个结点, 步数加一

p1 = p1->next;

count_01++;

}

return ERROR;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值