c++ 链表删除重复的数据
//List.h
#include <iostream> typedef int dataType; struct Node{ Node():data(0),pNextNode(NULL){} //结点构造函数 dataType data; Node* pNextNode; }; class List{ private: Node *head; //作为链表唯一的头指针 int size; //链表长度 public: List(){head=new Node;size=0;} bool isEmpty(); //判断是否空表 bool InsertList(int i,dataType elem); //i的指标从1开始,而不是从0开始 void PushList(dataType elem); //在链表尾部添加元素 bool DeleteList(int i); //删除指定位置的元素 void ClearList(); //清除整条链表 void DeleteRepetitiveData();//删除重复元素 void PrintList(); //按顺序输出链表 int GetSize(); Node* Fine(int i); //找到第i个结点并返回该结点的指针 Node* FinePre(int i); //找到第i个结点前的结点,返回指针 };
//List.cpp
#include "List.h" #include <iostream> #include <vector> using namespace std; //判断空表 bool List::isEmpty(){ if(head==NULL) return false; else return true; } //在第i位插入数据 bool List::InsertList(int i,dataType elem){ if (i<1) return false; else if(head==NULL||i==1)//如果是空表 { head->data=elem; size++; return true; } else if (i>size) //位标大于链表长度时,在尾部添加 { PushList(elem); return true; } else { Node *pre=Fine(i-1); Node *follow=Fine(i); Node *s=new Node; //为新结点申请内存 pre->pNextNode=s; //连接前结点 s->pNextNode=follow; //连接后结点 s->data=elem; size++; return true; } } //在尾部添加元素 void List::PushList(dataType elem){ if(head==NULL) { head=new Node; head->data=elem; size++; } else { Node *cur=head; while(cur->pNextNode) cur=cur->pNextNode; Node *s=new Node; cur->pNextNode=s; s->data=elem; size++; } } //打印链表 void List::PrintList(){ Node *cur=head; while (cur!=NULL) { cout<<cur->data<<" "; cur=cur->pNextNode; } cout<<endl; } //size int List::GetSize(){ return size; } //找到第i个结点 Node* List::Fine(int i){ if(i==1) return head; else { Node *cur=head; for (int pos=1;pos<i;pos++) cur=cur->pNextNode; return cur; } } //找到i的前一个个结点 Node* List::FinePre(int i){ if(i<2) { cout<<"参数必须大于等于2!"<<endl; return NULL; } else if(i==2) return head; else return Fine(i-1); } //删除第i个元素 bool List::DeleteList(int i){ if (i<1||i>size) //限制i的范围 return false; else if(i==1) { Node *temp=head; head=head->pNextNode; delete temp; size--; return true; } else { Node *cur=this->Fine(i); Node *pre=this->FinePre(i); pre->pNextNode=cur->pNextNode; //重新连接结点 delete cur; size--; return true; } } //清空整个链表 void List::ClearList(){ Node *temp=head; while (head!=NULL) { temp=head; head=head->pNextNode; delete temp; } size=0; } //删除重复元素 void List::DeleteRepetitiveData(){ int flag=0; //代码运行标志,0为未运行 if(size==1) //只有一个元素时跳出 return; Node *stand=head;//内循环结束后或者找到相同数据后才会指向下个结点 Node *cursor; //游标 vector<int>storge; for (int i=0;i<size;i++) { //用for循环是因为要得到被删除元素的位置 //采用握手式比较,算法的时间复杂度为O(n^2) cursor=stand->pNextNode; flag=0; while(cursor!=NULL) { if(stand->data==cursor->data) { stand=stand->pNextNode; flag=1; //将重复的数据的下标降序保存起来 storge.insert(storge.begin(),i+1); break; } else cursor=cursor->pNextNode; } if(!flag) stand=stand->pNextNode; } int itemp=storge.size(); while (itemp--) { this->DeleteList(storge.at(0));//提取下标,释放多余结点 storge.erase(storge.begin()); } storge.clear(); //释放vector内存 }
//main.cpp
#include "List.h" #include <iostream> using namespace std; void main(){ //List类测试代码 List list; list.InsertList(1,1); list.InsertList(5,3); list.InsertList(2,2); list.InsertList(4,4); list.PrintList(); //打印这4个元素 cout<<"链表的长度为:"<<list.GetSize()<<endl; cout<<"现在删除第2个元素"<<endl; list.DeleteList(2); list.PrintList(); cout<<"现在清空链表"<<endl; list.ClearList(); //清空链表 cout<<"输出空表:"<<endl; list.PrintList(); list.PushList(4); list.PushList(1); list.PushList(7); list.PushList(1); list.PushList(1); list.PushList(2); list.PushList(2); //压入4 1 7 1 1 2 2 cout<<"输出链表新加入的元素:"<<endl; list.PrintList(); cout<<"删除相同元素后的链表为:"<<endl; list.DeleteRepetitiveData(); list.PrintList(); } /* 总结: 1.链表类应该先写Fine()和FindPre(),再写插入和删除 2.链表的结构应该给每一个结点加上一个下标。因为下标在 操作时再加上的话,元素跟下标是不统一的, 如果有元素被删除,下标将要重新分配。
这就导致void List::DeleteRepetitiveData()不能用
相对直接的方法在检测到重复数据时就删除数据,而要借助vector
间接删除
*/