目录
1.题目
顺序表ADT模板简单应用算法设计:删除顺序表中的冗余元素
作者: 冯向阳时间限制: 1S章节: DS:线性表
问题描述 :
目的:使用自行设计的顺序表ADT或STL中的vector模板,设计并实现顺序表应用场合的一些简单算法设计。
应用3:试设计一个算法,删除非空顺序表L中的冗余元素,即使得操作之后的顺序表中只保留操作之前表中所有值都不相同的元素(提纯)。
参考函数原型:
(1)顺序表ADT版本
template<class ElemType>
void Purge_Sq( Sqlist<ElemType> &L );(2)vector版本
template<class ElemType>
void Purge_Sq( vector<ElemType> &L );输入说明 :
第一行:顺序表的数据元素类型标记(0:int;1:double;2:char;3:string;其余值:输出err)
第二行:待处理顺序表的数据元素(数据元素之间以空格分隔)
输出说明 :
第一行:提纯前顺序表的遍历结果(数据元素之间以“,”分隔)
空行
第二行:提纯后顺序表的遍历结果(数据元素之间以“,”分隔)
输入范例 :
0
13 5 13 9 32 51 76 5 9 8输出范例 :
13,5,13,9,32,51,76,5,9,8
13,5,9,32,51,76,8
2.题解
- 读题:用vector或者手写adt实现顺序表,并且实现顺序表冗余元素删除的算法。
- 造表:用第一题的代码(大懒人)
- 算法:我一开始脑子里蹦出stl中的set,它可以自己完成集合中去重,but我不太会用,有时间再想学一下然后实现。最无脑的去重无非就是两重循环,一重遍历表,第二重遍历此位置前的元素找出重复的然后删除。还有个简单点的方法就是使用vector里面的remove和erase函数。
3.代码实现
- 造表(直接复制粘贴第一题的,就省略了)
- 算法:
//打印函数 template<class T> void print(vector<T> &A) { int i; for(i=0; i<A.size()-1; i++) { cout<<A[i]<<","; } cout<<A[i]<<endl; } //去重函数模版 template<class T> void change(vector<T> &A) { print(A); cout<<endl; //法一,n*n的复杂度 for(int i=0; i<A.size(); i++) { for(int j=0; j<i; j++) { if(A[i]==A[j]) { A.erase(A.begin()+i); i--; break; } } } //法二,remove返回的是删除元素后表的最后一个位置,但没有真正删除,所以再用erase删一下 for(int i=0;i<A.size();i++) { A.erase(remove(A.begin()+1+i,A.end(),A[i]),A.end()); } print(A); }
- 完整代码
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <cstring> using namespace std; int n; string s; template<class T> void print(vector<T> &A) { int i; for(i=0; i<A.size()-1; i++) { cout<<A[i]<<","; } cout<<A[i]<<endl; } template<class T> void change(vector<T> &A) { print(A); cout<<endl; /*法一,n*n的复杂度 for(int i=0; i<A.size(); i++) { for(int j=0; j<i; j++) { if(A[i]==A[j]) { A.erase(A.begin()+i); i--; break; } } } 下面是法二 */ for(int i=0;i<A.size();i++) { A.erase(remove(A.begin()+1+i,A.end(),A[i]),A.end()); } print(A); } int main() { cin>>n; getchar(); getline(cin,s); if(n==0) { vector<int> a; int num=0; for(int i=0; i<s.size(); i++) { if(s[i]==' ') { a.push_back(num); num=0; } else { num=num*10+s[i]-'0'; } } a.push_back(num); change(a); } else if(n==1) { vector<double> b; double num=0; int flag=0,t=0; for(int i=0; i<s.size(); i++) { if(s[i]==' ') { num=num/pow(10,t); b.push_back(num); t=0,num=0,flag=0; } else if(s[i]=='.') { flag=1; } else { num=num*10+s[i]-'0'; if(flag==1) t++; } } num=num/pow(10,t); b.push_back(num); change(b); } else if(n==2) { vector<char> c; for(int i=0; i<s.size(); i++) { if(s[i]!=' ') c.push_back(s[i]); } change(c); } else if(n==3) { vector<string> d; string str; str.clear(); for(int i=0; i<s.size(); i++) { if(s[i]==' ') { d.push_back(str); str.clear(); } else str+=s[i]; } d.push_back(str); change(d); } else cout<<"err"<<endl; return 0; }
4.改进
- 理论:上面的两种算法时间复杂度都是O(n*n),时间复杂度比较高,现在进行一个去重算法的优化。众所周知,顺序表的缺点就是在进行非引用型的算法时(插入,删除等)需要有大动作的搬迁(一般这个搬迁会使得复杂度激增*n倍,所以如果顺序表算法中可以避免这种大动作搬迁,那么这个算法就能得到很好的优化。理论讲完了,来看看这个题目中算法怎么优化。
- 算法:对原顺序表每一个元素在新表(装去重后的元素)中进行查找,如果新表中没有出现过原表正在考察的元素则插入新表中,否则舍弃。同时,我们所说的新表可以与原表共享一个存储空间,只用不同的游标指针来区分是原表或者新表。
- 具体算法代码
template<class T> void dele(stringstream &in,vector<T> &A) { //造表 T str; while(in>>str)A.push_back(str); //输出原表 print(A); cout<<endl; //优化的去重算法 int i,j,k; k=-1;//k是新表的游标指针,指向新表尾部 for(i=0;i<A.size();i++)//遍历原表所有元素 { j=0;//用于考察新表的指针 while(j<=k && A[i]!=A[j])//新表未被查找完,并且正在考察的原表中的元素和次查询的新表中的元素并不相同,则继续考察新表剩余的元素 j++; if(k==-1 || j>k)//当插入新表第一个元素以及当正在考察的原表元素在新表中并未存在过(即这个元素不重复)就把它插入到新表中 A[++k]=A[i]; } //输出新表 for(i=0;i<k;i++)//新表长度为k+1 cout<<A[i]<<","; cout<<A[i]<<endl; }
- 优化后的完整代码
#include <iostream> #include <sstream> #include <vector> #include <cstring> using namespace std; template<class T> void print(vector<T> &A) { auto it=A.begin(); for(;it!=A.end();it++)cout<<*it<<","; cout<<*it<<endl; } template<class T> void dele(stringstream &in,vector<T> &A) { T str; while(in>>str)A.push_back(str); print(A); cout<<endl; int i,j,k; k=-1; for(i=0;i<A.size();i++) { j=0; while(j<=k && A[i]!=A[j]) j++; if(k==-1 || j>k) A[++k]=A[i]; } for(i=0;i<k;i++) cout<<A[i]<<","; cout<<A[i]<<endl; } int main() { int n; string s; cin>>n; getchar(); getline(cin,s); stringstream in(s); if(n==0) { vector<int> a; dele(in,a); } else if(n==1) { vector<double> b; dele(in,b); } else if(n==2) { vector<char> c; dele(in,c); } else if(n==3) { vector<string> d; dele(in,d); } else cout<<"err"<<endl; return 0; }