我一直在研究这个问题的时间超过了我现在想承认的时间,这让我疯了!给定一个简单的链表,比如说除了指向下一个节点(data
)的指针之外还存储一个整数(next
),我想要一个算法去除重复而不排序或依赖辅助功能。
以前的问题已经被问及Java中未分类的链表,它利用了Java提供的辅助功能。这与C完全相关,不使用辅助函数。
我已经修改了代码,并且已经将其用于某些情况,但不是全部。这是一个完整的,可验证的示例 - 我已经包含push()
函数来创建链接列表和main()
包含测试用例,但我的问题涉及的逻辑是{{{ 1}}单独:
removeDuplicates()
我还提供了一张描述逻辑的图片,如果不清楚我在做什么:http://imgur.com/DbnBOq2
答案 0 :(得分:2)
/* Program to remove duplicates in an unsorted linked list */
#include <bits/stdc++.h>
using namespace std;
/* A linked list node */
struct Node
{
int data;
struct Node *next;
};
// Utility function to create a new Node
struct Node *newNode(int data)
{
Node *temp = new Node;
temp->data = data;
temp->next = NULL;
return temp;
}
/* Function to remove duplicates from a
unsorted linked list */
void removeDuplicates(struct Node *start)
{
struct Node *ptr1, *ptr2, *dup;
ptr1 = start;
/* Pick elements one by one */
while (ptr1 != NULL && ptr1->next != NULL)
{
ptr2 = ptr1;
/* Compare the picked element with rest
of the elements */
while (ptr2->next != NULL)
{
/* If duplicate then delete it */
if (ptr1->data == ptr2->next->data)
{
/* sequence of steps is important here */
dup = ptr2->next;
ptr2->next = ptr2->next->next;
delete(dup);
}
else /* This is tricky */
ptr2 = ptr2->next;
}
ptr1 = ptr1->next;
}
}
/* Function to print nodes in a given linked list */
void printList(struct Node *node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
/* Druver program to test above function */
int main()
{
/* The constructed linked list is:
10->12->11->11->12->11->10*/
struct Node *start = newNode(10);
start->next = newNode(12);
start->next->next = newNode(11);
start->next->next->next = newNode(11);
start->next->next->next->next = newNode(12);
start->next->next->next->next->next =
newNode(11);
start->next->next->next->next->next->next =
newNode(10);
printf("Linked list before removing duplicates ");
printList(start);
removeDuplicates(start);
printf("\nLinked list after removing duplicates ");
printList(start);
return 0;
}
答案 1 :(得分:0)
这种问题在各种变体中被提出很多。通常当一个人实现一个链表时,最终会出现一个需要保持方式指向各种元素的指针的点。从表面上看,似乎单个重定向更容易使用,而实际上它并没有传达足够的关于列表的信息来在本地执行操作。
这是重写(但未经过全面测试)的功能,以利用“链接”抽象(基本上是struct node**
):
void removeDuplicates(struct node** head) {
if(!head)
return;
struct node **link = head;
// We will iterate over the links. I.e. the `next` pointers in the list.
while(*link) {
struct node **rest = &((*link)->next);
while(*rest) {
if ((*link)->data != (*rest)->data) {
rest = &((*rest)->next); // move to the next link
} else {
// modify the current link of rest to look one past the next
struct node *to_remove = *rest;
*rest = to_remove->next;
free(to_remove);
}
}
link = &((*link)->next); // again, move the the next link
}
}
通过使用另一个间接层,可以保证我们用于遍历列表的迭代器在任何时候都不会失效。没有办法(除非写错误)上面的循环可以使*link
无效,因此无需在作业link = &((*link)->next);
之前检查
答案 2 :(得分:0)
void removeDuplicates(struct node **head){
struct node *tmp;
while (*head) {
/* Look below *head, to see if it has any duplicates */
for (tmp= (*head)->next; tmp; tmp = tmp->next) {
if (tmp->data == (*head)->data) break;
}
/* Found no duplicate: advance head */
if(!tmp) { head = &(*head)->next; continue;}
/* Duplicate found :: delete *head */
tmp = (*head)->next;
free(*head);
*head = tmp;
}
return;
}
现在,查看角落案例:
答案 3 :(得分:0)
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *createNode(int data)
{
struct node *n;
n = (struct node *)malloc(sizeof(struct node));
n->data = data;
n->next = NULL;
return n;
}
void traverseList(struct node *head)
{
while (head != NULL)
{
printf("%d ", head->data);
head = head->next;
}
}
void removeDuplicates(struct node *head)
{
struct node *ptr = head;
while (ptr != NULL)
{
struct node *runner = ptr;
while (runner->next != NULL)
{
if (ptr->data == runner->next->data)
{
runner->next = runner->next->next;
}
else
{
runner = runner->next;
}
}
free(runner->next);
ptr = ptr->next;
}
}
int main()
{
struct node *node1, *node2, *node3, *node4;
node1 = createNode(2);
node2 = createNode(5);
node3 = createNode(5);
node4 = createNode(1);
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = NULL;
traverseList(node1);
removeDuplicates(node1);
printf("\n");
traverseList(node1);
return 0;
}
答案 4 :(得分:-3)
特别感谢@StoryTeller - 我还没有验证你的解决方案,但你对有太多指针的评论绝对是关键。我已经重新编写了我的函数,它现在适用于4种不同的特殊情况(列表末尾的复制品,列表的开头,整个列表中随机的列表,纯粹包含重复的列表)。这是正确的代码:
void removeDuplicates(struct node** head){
struct node* currentNode = *head;
struct node* runningNode = (*head)->next;
struct node* runningNodePrev = *head;
int count = -1;
while(currentNode->next != NULL){
count++;
if(count){
currentNode = currentNode->next;
runningNodePrev = currentNode;
runningNode = currentNode->next;
}
while(runningNode != NULL){
if(runningNode->data == currentNode->data){
runningNodePrev->next = runningNode->next;
free(runningNode);
runningNode = runningNodePrev->next;
}else{
runningNodePrev = runningNodePrev->next;
runningNode = runningNode->next;
}
}
}
}
干杯谢谢所有评论的人。