给定一个链表,检查链表是否有循环。下图显示了带有循环的链表。

专注于为中小企业提供网站建设、网站制作服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业宁德免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了千余家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
以下是执行此操作的不同方法
解决方案1:散列方法:
遍历该列表,并将节点地址始终放在哈希表中。在任何时候,如果达到NULL,则返回false,如果当前节点的下一个指向Hash中先前存储的任何节点,则返回true。
- #include
 - using namespace std;
 - struct Node {
 - int data;
 - struct Node* next;
 - };
 - void push(struct Node** head_ref, int new_data)
 - {
 - struct Node* new_node = new Node;
 - new_node->data = new_data;
 - new_node->next = (*head_ref);
 - (*head_ref) = new_node;
 - }
 - bool detectLoop(struct Node* h)
 - {
 - unordered_set
 s; - while (h != NULL) {
 - if (s.find(h) != s.end())
 - return true;
 - s.insert(h);
 - h = h->next;
 - }
 - return false;
 - }
 - int main()
 - {
 - struct Node* head = NULL;
 - push(&head, 20);
 - push(&head, 4);
 - push(&head, 15);
 - push(&head, 10);
 - head->next->next->next->next = head;
 - if (detectLoop(head))
 - cout << "Loop found";
 - else
 - cout << "No Loop";
 - return 0;
 - }
 
复杂度分析:
时间复杂度: O(n)。 
 只需循环一次即可。
辅助空间: O(n)。 
 n是将值存储在哈希图中所需的空间。
解决方案2:通过修改链表数据结构,无需哈希图即可解决此问题。 
 方法:此解决方案需要修改基本链表数据结构。
C++:
- #include
 - using namespace std;
 - struct Node {
 - int data;
 - struct Node* next;
 - int flag;
 - };
 - void push(struct Node** head_ref, int new_data)
 - {
 - struct Node* new_node = new Node;
 - new_node->data = new_data;
 - new_node->flag = 0;
 - new_node->next = (*head_ref);
 - (*head_ref) = new_node;
 - }
 - bool detectLoop(struct Node* h)
 - {
 - while (h != NULL) {
 - if (h->flag == 1)
 - return true;
 - h->flag = 1;
 - h = h->next;
 - }
 - return false;
 - }
 - int main()
 - {
 - struct Node* head = NULL;
 - push(&head, 20);
 - push(&head, 4);
 - push(&head, 15);
 - push(&head, 10);
 - head->next->next->next->next = head;
 - if (detectLoop(head))
 - cout << "Loop found";
 - else
 - cout << "No Loop";
 - return 0;
 - }
 
复杂度分析:
时间复杂度: O(n)。 
 只需循环一次即可。
辅助空间: O(1)。 
 不需要额外的空间。
解决方案3:Floyd的循环查找算法 
 方法:这是最快的方法,下面进行了介绍:
Floyd的循环查找算法的实现:
- #include
 - using namespace std;
 - class Node {
 - public:
 - int data;
 - Node* next;
 - };
 - void push(Node** head_ref, int new_data)
 - {
 - Node* new_node = new Node();
 - new_node->data = new_data;
 - new_node->next = (*head_ref);
 - (*head_ref) = new_node;
 - }
 - int detectLoop(Node* list)
 - {
 - Node *slow_p = list, *fast_p = list;
 - while (slow_p && fast_p && fast_p->next) {
 - slow_p = slow_p->next;
 - fast_p = fast_p->next->next;
 - if (slow_p == fast_p) {
 - return 1;
 - }
 - }
 - return 0;
 - }
 - int main()
 - {
 - Node* head = NULL;
 - push(&head, 20);
 - push(&head, 4);
 - push(&head, 15);
 - push(&head, 10);
 - head->next->next->next->next = head;
 - if (detectLoop(head))
 - cout << "Loop found";
 - else
 - cout << "No Loop";
 - return 0;
 - }
 
解决方案4:在不修改链接列表数据结构的情况下标记访问的节点 
 在此方法中,将创建一个临时节点。使遍历的每个节点的下一个指针指向该临时节点。这样,我们将节点的下一个指针用作标志来指示该节点是否已遍历。检查每个节点以查看下一个节点是否指向临时节点。在循环的第一个节点的情况下,第二次遍历该条件将成立,因此我们发现该循环存在。如果遇到一个指向null的节点,则循环不存在。
 下面是上述方法的实现:
- #include
 - using namespace std;
 - struct Node {
 - int key;
 - struct Node* next;
 - };
 - Node* newNode(int key)
 - {
 - Node* temp = new Node;
 - temp->key = key;
 - temp->next = NULL;
 - return temp;
 - }
 - void printList(Node* head)
 - {
 - while (head != NULL) {
 - cout << head->key << " ";
 - head = head->next;
 - }
 - cout << endl;
 - }
 - bool detectLoop(Node* head)
 - {
 - Node* temp = new Node;
 - while (head != NULL) {
 - if (head->next == NULL) {
 - return false;
 - }
 - if (head->next == temp) {
 - return true;
 - }
 - Node* nex = head->next;
 - head->next = temp;
 - head = nex;
 - }
 - return false;
 - }
 - int main()
 - {
 - Node* head = newNode(1);
 - head->next = newNode(2);
 - head->next->next = newNode(3);
 - head->next->next->next = newNode(4);
 - head->next->next->next->next = newNode(5);
 - head->next->next->next->next->next = head->next->next;
 - bool found = detectLoop(head);
 - if (found)
 - cout << "Loop Found";
 - else
 - cout << "No Loop";
 - return 0;
 - }
 
复杂度分析:
时间复杂度: O(n)。 
 只需循环一次即可。
辅助空间: O(1)。 
 不需要空间。
解决方案5:存放长度
在此方法中,将创建两个指针,第一个(始终指向头)和最后一个指针。每次最后一个指针移动时,我们都会计算第一个和最后一个之间的节点数,并检查当前节点数是否大于先前的节点数,如果是,我们通过移动最后一个指针进行操作,否则就意味着我们已经到达循环的终点,因此我们相应地返回输出。
- #include
 - using namespace std;
 - struct Node {
 - int key;
 - struct Node* next;
 - };
 - Node* newNode(int key)
 - {
 - Node* temp = new Node;
 - temp->key = key;
 - temp->next = NULL;
 - return temp;
 - }
 - void printList(Node* head)
 - {
 - while (head != NULL) {
 - cout << head->key << " ";
 - head = head->next;
 - }
 - cout << endl;
 - }
 - int distance(Node* first, Node* last)
 - {
 - int counter = 0;
 - Node* curr;
 - curr = first;
 - while (curr != last) {
 - counter += 1;
 - curr = curr->next;
 - }
 - return counter + 1;
 - }
 - bool detectLoop(Node* head)
 - Node* temp = new Node;
 - Node *first, *last;
 - first = head;
 - last = head;
 - int current_length = 0;
 - int prev_length = -1;
 - while (current_length > prev_length && last != NULL) {
 - prev_length = current_length;
 - current_length = distance(first, last);
 - last = last->next;
 - }
 - if (last == NULL) {
 - return false;
 - }
 - else {
 - return true;
 - }
 - }
 - int main()
 - {
 - Node* head = newNode(1);
 - head->next = newNode(2);
 - head->next->next = newNode(3);
 - head->next->next->next = newNode(4);
 - head->next->next->next->next = newNode(5);
 - head->next->next->next->next->next = head->next->next;
 - bool found = detectLoop(head);
 - if (found)
 - cout << "Loop Found";
 - else
 - cout << "No Loop Found";
 - return 0;
 - }
 
}
                名称栏目:五个解决办法教你C++中检测链表中的循环
                
                链接地址:http://www.csdahua.cn/qtweb/news7/29907.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网