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;
}