C:从未排序的链表中删除重复项

C:从未排序的链表中删除重复项,c,linked-list,duplicates,C,Linked List,Duplicates,我已经在这个问题上工作了超过我现在承认的时间,这让我发疯了!给定一个简单的链表,比如除了指向下一个节点(next)的指针之外,还存储了一个整数(data),我希望有一个算法可以删除重复项,而无需排序或依赖辅助函数 前面的问题是关于Java中未排序的链表的,这些链表利用了Java提供的帮助函数。这与不使用辅助函数的C语言密切相关 我已经对代码进行了修补,并且在某些情况下可以使用,但不是所有情况下都可以。这里是一个完整的、可验证的示例——我已经包括了一个push()函数来创建一个链表和一个带有测试用

我已经在这个问题上工作了超过我现在承认的时间,这让我发疯了!给定一个简单的链表,比如除了指向下一个节点(
next
)的指针之外,还存储了一个整数(
data
),我希望有一个算法可以删除重复项,而无需排序或依赖辅助函数

前面的问题是关于Java中未排序的链表的,这些链表利用了Java提供的帮助函数。这与不使用辅助函数的C语言密切相关

我已经对代码进行了修补,并且在某些情况下可以使用,但不是所有情况下都可以。这里是一个完整的、可验证的示例——我已经包括了一个
push()
函数来创建一个链表和一个带有测试用例的
main()
,但是我的问题所涉及的逻辑仅在
removeDuplicates()
中:

#include <stdlib.h>
#include <stdio.h>

struct node {
    int data;
    struct node *next; 
};

void push(struct node **headRef, int data) {
    struct node *newNode = malloc(sizeof(struct node));
    newNode->data = data;
    newNode->next = *headRef;
    *headRef = newNode;
}

void removeDuplicates(struct node **head) {
        struct node *currentNode = *head; //The node we compare other nodes against
    struct node *runningNode = (*head)->next; //The node we are comparing to
    struct node *runningNodePrev = *head; //The node before the node we are comparing to
    struct node *runningNodeNext = (*head)->next->next; // The node after the node we are comparing to
    int count = -1;
    while (currentNode->next != NULL) { //Ensure we are not looking at the last node -- cannot have comparisons past this node
        count++;
        if (count) {
            //'Base Position'
            currentNode = currentNode->next;
            runningNodePrev = currentNode;
            runningNode = currentNode->next;
            runningNodeNext = runningNode->next;
        }
        printf("\nChecking for a match with  %d ... \n", currentNode->data);
        while (runningNode != NULL) { //Compare each node in the list until we reach the end of the list
            printf("Inspecting next adjacent node ... \n");
            if (runningNode->data == currentNode->data) {//If a duplicate is found
                printf("Found match ... ");

                //Ensure link is maintained before removing duplicate node
                if (currentNode == runningNodePrev)
                    currentNode->next = runningNodeNext;
                runningNodePrev->next = runningNodeNext; 

                free(runningNode);//Delete duplicate node
                printf("Deleted duplicate.\n");
            }
            runningNode = runningNodeNext;//Continue searching for duplicates at the first unchecked node
            runningNodeNext = runningNodeNext->next;//Move running node leader up the list.     
        }
    }
}

int main(void) {
    struct node *t1 = NULL;
    struct node *t2 = NULL;
    struct node *t4 = NULL;
    struct node *t5 = NULL;
    push(&t1, 1);
    push(&t1, 1);
    push(&t1, 1);
    push(&t1, 1);
    push(&t2, 6);
    push(&t2, 1);
    push(&t2, 2);
    push(&t2, 3);
    push(&t2, 4);
    push(&t2, 5);
    push(&t2, 6);
    push(&t4, 4);
    push(&t4, 2);
    push(&t4, 3);
    push(&t4, 2);
    push(&t4, 1);
    push(&t5, 0);
    push(&t5, 0);
    push(&t5, 1);
    printf("Testing removeDuplicates()...\n");
    printf("Case 1: Calling removeDuplicates({1,0,0}).\n");
    printf("Expected result: { 1 0 }\n");
    printf("Actual result:   { ");
    removeDuplicates(&t5);
    ptr = t5;
    while (ptr != NULL) { 
        printf("%d ", ptr->data);
        ptr = ptr->next;
    }
    printf("}\n");
    printf("Case 2: Calling removeDuplicates({1,2,3,2,4}).\n");
    printf("Expected result: { 1 2 3 4 }\n");
    printf("Actual result:   { ");
    removeDuplicates(&t4);
    ptr = t4;
    while (ptr != NULL) {
        printf("%d ", ptr->data);
        ptr = ptr->next;
    }
    printf("}\n");
    printf("Case 3: Calling removeDuplicates({6,5,4,3,2,1,6}).\n");
    printf("Expected result: { 6 5 4 3 2 1 }\n");
    printf("Actual result:   { ");
    removeDuplicates(&t2);
    ptr = t2;
    while (ptr != NULL) {
        printf("%d ", ptr->data);
        ptr = ptr->next;
    }
    printf("}\n");
    printf("Case 4: Calling removeDuplicates({1,1,1,1}).\n");
    printf("Expected result: { 1 }\n");
    printf("Actual result:   { ");
    removeDuplicates(&t1);
    ptr = t1;
    while (ptr != NULL) {
        printf("%d ", ptr->data);
        ptr = ptr->next;
    }
    printf("}\n");
}
#包括
#包括
结构节点{
int数据;
结构节点*下一步;
};
无效推送(结构节点**headRef,int数据){
结构节点*newNode=malloc(sizeof(结构节点));
新建节点->数据=数据;
新建节点->下一步=*headRef;
*headRef=newNode;
}
移除的无效副本(结构节点**头){
struct node*currentNode=*head;//将其他节点与之进行比较的节点
struct node*runningNode=(*head)->next;//我们要比较的节点
struct node*runningNodePrev=*head;//我们要比较的节点之前的节点
struct node*runningNodeNext=(*head)->next->next;//我们要比较的节点后面的节点
整数计数=-1;
while(currentNode->next!=NULL){//请确保我们没有查看最后一个节点——不能通过此节点进行比较
计数++;
如果(计数){
//“基本位置”
currentNode=currentNode->next;
runningNodePrev=currentNode;
runningNode=currentNode->next;
runningNodeNext=runningNode->next;
}
printf(“\n检查与%d的匹配…\n”,currentNode->data);
while(runningNode!=NULL){//比较列表中的每个节点,直到到达列表的末尾
printf(“检查下一个相邻节点…\n”);
如果(runningNode->data==currentNode->data){//如果发现重复项
printf(“找到匹配项…”);
//确保在删除重复节点之前保持链接
if(currentNode==runningNodePrev)
currentNode->next=runningNodeNext;
runningNodePrev->next=runningNodeNext;
free(runningNode);//删除重复的节点
printf(“已删除的副本。\n”);
}
runningNode=runningNodeNext;//继续在第一个未选中的节点上搜索重复项
runningNodeNext=runningNodeNext->next;//将正在运行的节点前导向上移动到列表中。
}
}
}
内部主(空){
结构节点*t1=NULL;
结构节点*t2=NULL;
结构节点*t4=NULL;
结构节点*t5=NULL;
推送(&t1,1);
推送(&t1,1);
推送(&t1,1);
推送(&t1,1);
推(t2,6);
推送(&t2,1);
推送(&t2,2);
推(t2,3);
推送(&t2,4);
推(t2,5);
推(t2,6);
推送(&t4,4);
推送(&t4,2);
推送(&t4,3);
推送(&t4,2);
推送(&t4,1);
推送(&t5,0);
推送(&t5,0);
推送(&t5,1);
printf(“测试移除的副本()…\n”);
printf(“案例1:调用removeDuplicates({1,0,0})。\n”);
printf(“预期结果:{10}\n”);
printf(“实际结果:{”);
移除的副本(&t5);
ptr=t5;
while(ptr!=NULL){
printf(“%d”,ptr->data);
ptr=ptr->next;
}
printf(“}\n”);
printf(“情况2:调用移除的副本({1,2,3,2,4})。\n”);
printf(“预期结果:{1 2 3 4}\n”);
printf(“实际结果:{”);
移除的副本(&t4);
ptr=t4;
while(ptr!=NULL){
printf(“%d”,ptr->data);
ptr=ptr->next;
}
printf(“}\n”);
printf(“情况3:调用移除的副本({6,5,4,3,2,1,6})。\n”);
printf(“预期结果:{654321}\n”);
printf(“实际结果:{”);
移除的副本(&t2);
ptr=t2;
while(ptr!=NULL){
printf(“%d”,ptr->data);
ptr=ptr->next;
}
printf(“}\n”);
printf(“情况4:调用removeDuplicates({1,1,1,1})。\n”);
printf(“预期结果:{1}\n”);
printf(“实际结果:{”);
移除的副本(&t1);
ptr=t1;
while(ptr!=NULL){
printf(“%d”,ptr->data);
ptr=ptr->next;
}
printf(“}\n”);
}

我还附上了一张图片,描述了如果不清楚我在做什么时的逻辑:

这类问题被问了很多不同的问题。通常,当一个人在实现一个链表时,最终会遇到一个需要保留太多指向不同元素的指针的问题。从表面上看,单个重定向似乎更容易处理,但实际上它无法传递足够的列表信息,无法在本地执行操作

下面是重新编写(但未完全测试)的函数,以利用“链接”抽象(本质上是一个
struct节点**
):


通过使用另一级别的间接寻址,可以保证用于遍历列表的迭代器在任何时候都不会失效。上面的循环不可能使
*link
无效(除非编写时出错),因此在分配
link=&(*link)->next之前不需要检查

这类问题被问了很多不同的问题。通常,当一个人在实现一个链表时,最终会遇到一个需要保留太多指向不同元素的指针的问题。从表面上看,单个重定向似乎更容易使用,而
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
  }
}
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;
}
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;
            }
        }
    }
}
/* 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;
}
#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;
}