C 我有一个链表,我想删除重复的值

C 我有一个链表,我想删除重复的值,c,algorithm,struct,linked-list,singly-linked-list,C,Algorithm,Struct,Linked List,Singly Linked List,所以,我创建了一个代码,它创建了一个包含5个值的链表。我想知道什么是最好的方法来删除这些值的重复项,并在没有重复项的情况下再次打印链接列表 #include <stdio.h> #include <stdlib.h> /* self-referential structure*/ struct studentID{ int value; //a data member which is an integer struct student

所以,我创建了一个代码,它创建了一个包含5个值的链表。我想知道什么是最好的方法来删除这些值的重复项,并在没有重复项的情况下再次打印链接列表

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

/* self-referential structure*/
struct studentID{
    int value;          //a data member which is an integer
    struct studentID *next;         //a data member which is a pointer to next node
};


typedef struct studentID STUDENTID;     //creating a nickname for struct studentID as STUDENTID
typedef STUDENTID *STUDENTIDPtr;        //creating a nickname for STUDENTID as STUDENTIDPtr


//Global variables
STUDENTIDPtr previousPtr;           //pointer to previous node in list
STUDENTIDPtr currentPtr;            //pointer to current node in list


void printList(STUDENTIDPtr currentPtr){


    while (currentPtr != NULL){         //while not the end of the list
        printf("%d -> ", currentPtr->value);
        currentPtr = currentPtr ->next;
    }
}


int main(){
    STUDENTIDPtr newPtr1;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr2;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr3;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr4;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr5;           //creating a pointer to create a new node


    //creation of the first node
    newPtr1 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr2 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr3 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr4 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr5 = malloc(sizeof(STUDENTID));            //This is when a node is created


    newPtr1 -> value = 4; // assign data in first node 
    newPtr1 -> next = newPtr2;


    newPtr2 -> value = 4; // assign data in first node 
    newPtr2 -> next = newPtr3;


    newPtr3 -> value = 5; // assign data in first node 
    newPtr3 -> next = newPtr4;


    newPtr4 -> value = 2; // assign data in first node 
    newPtr4 -> next = newPtr5;


    newPtr5 -> value = 1; // assign data in first node 
    newPtr5 -> next = NULL;


    currentPtr = newPtr1;

    printList(newPtr1);


    return 0;
}

#包括
#包括
/*自指结构*/
结构学生ID{
int value;//是整数的数据成员
struct studentID*next;//是指向下一个节点的指针的数据成员
};
typedef struct studentID studentID//将struct studentID的昵称创建为studentID
typedef STUDENTID*STUDENTIDPtr//将STUDENTID的昵称创建为STUDENTIDPtr
//全局变量
学生先前的PTR//指向列表中上一个节点的指针
学生英语//指向列表中当前节点的指针
无效打印列表(STUDENTIDPtr currentPtr){
while(currentpr!=NULL){//而不是列表的末尾
printf(“%d->”,currentPtr->value);
currentPtr=currentPtr->next;
}
}
int main(){
STUDENTIDPtr newPtr1;//创建指针以创建新节点
STUDENTIDPtr newPtr2;//创建指针以创建新节点
STUDENTIDPtr newPtr3;//创建指针以创建新节点
STUDENTIDPtr newPtr4;//创建指针以创建新节点
STUDENTIDPtr newPtr5;//创建指针以创建新节点
//创建第一个节点
newPtr1=malloc(sizeof(STUDENTID));//这是创建节点的时间
newPtr2=malloc(sizeof(STUDENTID));//这是创建节点的时间
newPtr3=malloc(sizeof(STUDENTID));//这是创建节点的时间
newPtr4=malloc(sizeof(STUDENTID));//这是创建节点的时间
newPtr5=malloc(sizeof(STUDENTID));//这是创建节点的时间
newPtr1->value=4;//在第一个节点中分配数据
newPtr1->next=newPtr2;
newPtr2->value=4;//在第一个节点中分配数据
newPtr2->next=newPtr3;
newPtr3->value=5;//在第一个节点中分配数据
newPtr3->next=newPtr4;
newPtr4->value=2;//在第一个节点中分配数据
newPtr4->next=newPtr5;
newPtr5->value=1;//在第一个节点中分配数据
newPtr5->next=NULL;
currentPtr=newPtr1;
打印列表(newPtr1);
返回0;
}

使用if-else和run-through每个链表是容易的还是有更好的方法?

有两种方法会马上浮现在脑海中,使用哪种方法取决于您的具体情况,以及您是否希望保留元素的原始顺序


第一种方法:

使用双循环,一次拾取一个节点。然后迭代该节点之后的列表,如果发现重复的,则删除。重复拾取节点,直到遍历整个列表

For every node of the list
  For every next_node after node
    If next_node.value == node.value
      Remove that next_node
这种方法保留了元素的原始顺序

我认为这种方法是你已经想到的。我建议你从这个开始

例如:

1->2->3->4->1

我将从第一个节点(1)开始,检查第二个节点、第三个节点、第四个节点,到目前为止没有发现任何重复的节点。我现在检查第五个节点,它也有值1(发现重复!),所以我将其删除

现在列表如下所示:

1->2->3->4

现在我正在寻找第二个节点的副本(我在上一次遍历中检查了第一个节点)。我查了3,我查了4,没有发现重复的。名单保持不变

现在我正在寻找第三个节点的副本。我查了4个,没有发现重复的。名单保持不变

现在我正在寻找第四个节点的副本。下一个节点为NULL,这意味着第四个节点是最后一个节点(因为我们在第一次遍历中删除了第五个节点,作为1的副本)。没有什么可检查的,列表保持不变:

1->2->3->4

观察对于我要检查是否存在重复项的每个节点,我如何遍历列表直到其结束。因此,对于每个节点,我都在进行O(N)遍历,其中N是列表的大小

我有多少个节点?N

所以这种方法的时间复杂度是N*O(N)=O(N2)

我强烈建议你自己尝试一下,然后练习。完成后,您可以阅读以检查解决方案


第二种方法:

对列表进行排序,现在列表将把重复的值分组在一起。因此,如果存在当前节点的副本,它将是其下一个节点。如果是重复节点,请删除下一个节点

现在,同样,如果当前节点有一个副本,它将是它的下一个节点。因此,执行上述操作,直到下一个节点不是当前节点的副本

然后,使下一个节点成为当前节点,并执行相同的过程

Sort list
current_node = head_node
While current_node != NULL
  If current_node.value == current_node.next.value
    Remove current_node.next
  Else
    current_node = current_node.next
这种方法不保留元素的原始顺序

同样的例子:

1->2->3->4->1

对列表进行排序:

1->1->2->3->4

我从1开始。我检查它的下一个节点,它也是1,一个重复的发现!删除下一个节点。现在名单是:

1->2->3->4

当前节点仍然是1。我检查它的下一个节点,它是2。不是复制品。名单保持不变。将下一个节点设置为当前节点

当前节点为2。检查下一个节点,它是3,不是重复的。名单保持不变。将下一个节点设置为当前节点

当前节点为3。检查下一个节点,它是4,不是重复的。名单保持不变。将下一个节点设置为当前节点

当前节点为4。它没有下一个节点,无需检查,我已完成。名单不变:

1->2->3->4

请注意,对于每个节点,我只检查其紧邻的下一个节点。然后,我继续检查最后一个节点。这就是O(N)

但是,我必须对列表进行排序,以确保重复的列表是正确的
//Global variables
STUDENTIDPtr previousPtr;           //pointer to previous node in list
STUDENTIDPtr currentPtr;            //pointer to current node in list
typedef STUDENTID *STUDENTIDPtr; 
#include <stdio.h>
#include <stdlib.h>

/* self-referential structure*/
struct studentID{
    int value;          //a data member which is an integer
    struct studentID *next;         //a data member which is a pointer to next node
};


typedef struct studentID STUDENTID;     //creating a nickname for struct studentID as STUDENTID
typedef STUDENTID *STUDENTIDPtr;  

size_t remove_duplicates( STUDENTIDPtr *head )
{
    size_t n = 0;

    for ( ; *head != NULL; head = &( *head )->next )
    {
        for ( STUDENTIDPtr *next = &( *head )->next; *next != NULL; )
        {
            if ( ( *head )->value == ( *next )->value )
            {
                STUDENTIDPtr tmp = *next;
                *next = ( *next )->next;
                free( tmp );
                ++n;
            }
            else
            {
                next = &( *next )->next;
            }
        }
    }

    return n;
}

void printList(STUDENTIDPtr currentPtr){


    for ( ; currentPtr != NULL; currentPtr = currentPtr ->next )
    {
        printf("%d -> ", currentPtr->value);
    }

    puts( "NULL" );
}

int main(void) 
{
    STUDENTIDPtr newPtr1;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr2;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr3;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr4;           //creating a pointer to create a new node
    STUDENTIDPtr newPtr5;           //creating a pointer to create a new node


    //creation of the first node
    newPtr1 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr2 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr3 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr4 = malloc(sizeof(STUDENTID));            //This is when a node is created
    newPtr5 = malloc(sizeof(STUDENTID));            //This is when a node is created


    newPtr1 -> value = 4; // assign data in first node 
    newPtr1 -> next = newPtr2;


    newPtr2 -> value = 4; // assign data in first node 
    newPtr2 -> next = newPtr3;


    newPtr3 -> value = 5; // assign data in first node 
    newPtr3 -> next = newPtr4;


    newPtr4 -> value = 2; // assign data in first node 
    newPtr4 -> next = newPtr5;


    newPtr5 -> value = 1; // assign data in first node 
    newPtr5 -> next = NULL;


    printList( newPtr1 );

    size_t n = remove_duplicates( &newPtr1 );

    printf( "There are removed %zu elements\n", n );

    printList( newPtr1 );

    return 0;
}
4 -> 4 -> 5 -> 2 -> 1 -> NULL
There are removed 1 elements
4 -> 5 -> 2 -> 1 -> NULL