单链表ADT模板简单应用算法设计:有序单链表的提纯
时间限制: 1S类别: DS:线性表->链式线性表--简单
晚于: 2023-04-09 23:55:00后提交分数乘系数50%
问题描述 :
目的:使用C++模板设计单链表的抽象数据类型(ADT)。并在此基础上,使用单链表ADT的基本操作,设计并实现单链表的简单算法设计。
内容:(1)请使用模板设计单链表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的ADT原型文件。)
(2)ADT的简单应用:使用该ADT设计并实现单链表应用场合的一些简单算法设计。
应用5:试设计一个算法,删除有序单链表A中的冗余元素,即使得操作之后的单链表中只保留操作之前表中所有值都不相同的元素,并保持其有序性。要求利用原表中的结点,并释放A表中冗余的结点空间。
参考函数原型:
template<class ElemType>
void Purge_Lk_OL( LinkList<ElemType> &A ); //测试数据限定为整数。实际应用时,不受其限制
输入说明 :
第一行:顺序表A的数据元素的数据类型标记(0:int,1:double,2:char,3:string)
第二行:单链表A的数据元素(数据元素之间以空格分隔)
输出说明 :
如第一行输入值为0、1、2、3之外的值,直接输出“err”
否则:
第一行:单链表A的遍历结果
空行
第三行:提纯后单链表A的遍历结果
输入范例 :
0
3 3 5 5 8 11 11
输出范例 :
3->3->5->5->8->11->11
3->5->8->11
我的最终AC代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXSIZE=1000;
template<class ElemType>
struct LinkNode
{
ElemType data;
LinkNode<ElemType> *next;
LinkNode(LinkNode<ElemType> *ptr = NULL){next = ptr;} //构造函数1,用于构造头结点
LinkNode(const ElemType &item, LinkNode<ElemType> *ptr = NULL) //构造函数2,用于构造其他结点
//函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
{
next = ptr;
data = item;
}
//int getNum(){ return number; } //取得结点的序号
ElemType getData(){ return data; } //取得结点的数据域的值
void SetLink( LinkNode<ElemType> *link ){ next = link; } //修改结点的next域
void SetLink( ElemType value ){ data = value; } //修改结点的next域
};
//带头结点的循环单链表
template<class ElemType>
class LinkList{
private:
LinkNode<ElemType> *head; // 头结点
LinkNode<ElemType> *tail; // 尾结点
public:
//无参数的构造函数
LinkList(){head = new LinkNode<ElemType>; tail = head; head->next = head;}
//带参数的构造函数
LinkList(const ElemType &item){head = new LinkNode<ElemType>(item); tail = head; head->next = head;}
//拷贝构造函数
LinkList(LinkList<ElemType> &List);
//析构函数
~LinkList(){}
//销毁链表
void ListDestroy()
{
LinkNode<ElemType> *temp = NULL;
while(head)
{
temp = head->next;
delete head;
head = temp;
}
}
//清空链表
void ListClear();
//返回链表的长度
int ListLength() const;
//判断链表是否为空表
bool ListEmpty() const
{
//判断链表是否为空
if(head->next == NULL) return true;
return false;
}
//获取循环链表头结点
LinkNode<ElemType>* GetHead()
{
return head->next;
}
//获取循环链表尾结点
LinkNode<ElemType>* GetTail() { return tail;}
//设置链表头结点
void SetHead(LinkNode<ElemType> *p){ head = p;}
//在链表的第pos个位置之后插入e元素
bool ListInsert_next(int pos,ElemType e);
//在首结点之前插入一个结点
bool InsFirst( ElemType &e );
//在尾结点之前插入一个结点
bool InsTail( ElemType &e );
//表头插入法动态生成链表
void CreateList_Head(vector<ElemType> &A);
//表尾插入法动态生成链表
void Set11(LinkNode<ElemType>*a)
{
head=a;
}
void CreateList_Tail(vector<ElemType> &A)
{
LinkNode<ElemType> *r; //r为指向尾结点的指针
r = head;
LinkNode<ElemType> *p; //p为指向待插入结点的指针
for(typename vector<ElemType>::iterator it=A.begin(); it!=A.end(); it++)
{
p = new LinkNode<ElemType>;
p->data = *it;
r->next = p;
r = p;
}
r->next = 0;
tail = r;
}
//遍历链表
bool ListTraverse() const
{
//遍历链表
LinkNode<ElemType> *p;
p = head->next;
while( p )
{
cout<<p->data;
if(p->next!=NULL)
cout<<"->";
p = p->next;
} // while
cout<<endl;
return true;
}
void *shan()
{
LinkNode <ElemType> *p0=head->next;
LinkNode <ElemType> *p1;
LinkNode<ElemType> *p2;
for(;p0!=0&&p0->next!=0;p0=p0->next)
{
for(p2=p0,p1= p0->next;p1!=0;)
{
if(p0->data==p1->data)
{
LinkNode <ElemType>*p3=p1;
p1=p1->next;
p2->next=p1;
delete p3;
if(p1==0)
{
break;
}
continue;
}
p2=p1,p1= p1->next;
}
}
}
};
//函数
template<class ElemType>
void Purge_Lk_OL( LinkList<ElemType> &a )
{
a.shan();
}
int main() {
int i=1,sum,w;
cin>>w;
if (w == 0)
{
int n;
vector<int> a;
while(cin>>n)
{
a.push_back(n);
if (cin.get() == '\n')
break;
}
LinkList <int>s1;
s1.CreateList_Tail(a);
s1.ListTraverse();
cout<<endl;
Purge_Lk_OL(s1);
s1.ListTraverse();
}
else if (w == 1)
{
double n;
vector<double> a;
while(cin>>n)
{
a.push_back(n);
if (cin.get() == '\n')
break;
}
LinkList <double>s1;
s1.CreateList_Tail(a);
s1.ListTraverse();
cout<<endl;
Purge_Lk_OL(s1);
s1.ListTraverse();
}
else if (w == 2)
{
char n;
vector<char> a;
while(cin>>n)
{
a.push_back(n);
if (cin.get() == '\n')
break;
}
LinkList <char>s1;
s1.CreateList_Tail(a);
s1.ListTraverse();
cout<<endl;
Purge_Lk_OL(s1);
s1.ListTraverse();
}
else if(w==3)
{
string n;
cin.get();
getline(cin,n);
stringstream stream;
vector <string> a;
LinkList <string>s1;
for(int i=0,j=0;j<n.length();j++)
{
if(n[j]==' ')
{
stream<<n.substr(i,j-i);
string e;
stream>>e;
i=j+1;
a.push_back(e);
stream.clear();
}
else if(j==n.length()-1)
{
stream<<n.substr(i,j-i+1);
string e;
stream>>e;
a.push_back(e);
stream.clear();
}
}
s1.CreateList_Tail(a);
s1.ListTraverse();
cout<<endl;
Purge_Lk_OL(s1);
s1.ListTraverse();
}
else
{
cout << "err";
}
return 0;
}
对于线性表内的void *shan( )我有三次改动:
void *shan()
{
LinkNode <ElemType> *p0=head->next;
LinkNode <ElemType> *p1;
LinkNode<ElemType> *p2;
for(;p0->next!=0;p0=p0->next)
{
for(p2=p0,p1= p0->next;p1!=0;p2=p1,p1= p1->next)
{
if(p0->data==p1->data)
{
LinkNode <ElemType>*p3=p1;
p1=p1->next;
p2->next=p1;
delete p3;
}
}
}
}
};
第一次:我发现如果输入的是
1
1 2 3 4 1
那么在第二重循环里面的p1则会先指向null,在执行第二重for语句中又会指向null->next,在这里出现了PE的重大错误
于是我将其改为
void *shan()
{
LinkNode <ElemType> *p0=head->next;
LinkNode <ElemType> *p1;
LinkNode<ElemType> *p2;
for(;p0->next!=0;p0=p0->next)
{
for(p2=p0,p1= p0->next;p1!=0;p2=p1,p1= p1->next;)
{
if(p0->data==p1->data)
{
LinkNode <ElemType>*p3=p1;
p1=p1->next;
p2->next=p1;
delete p3;
if(p1==0)//这里跳出循环的条件有改变
{
break;
}
}
}
}
}
};
我又发现如果输入
1
1 2 3 4 4
那么再删掉最后一个4之后,p0先在第二重循环内指向null,在第一重循环中又指向了null->next,出现PE。
于是改为
void *shan()
{
LinkNode <ElemType> *p0=head->next;
LinkNode <ElemType> *p1;
LinkNode<ElemType> *p2;
for(;p0!=0&&p0->next!=0;p0=p0->next)//这里跳出循环的条件有改变
{
for(p2=p0,p1= p0->next;p1!=0;p2=p1,p1= p1->next;)
{
if(p0->data==p1->data)
{
LinkNode <ElemType>*p3=p1;
p1=p1->next;
p2->next=p1;
delete p3;
if(p1==0)
{
break;
}
}
}
}
}
};
此时已经大部分案例都AC了,只有一个WA,最后我发现问题在于:
如果我输入
0
1 1 1 1 1 1
最后结果为
1->1
不能将全部重复删掉,出现了指针多挪位的问题
所以我将其改为:
void *shan()
{
LinkNode <ElemType> *p0=head->next;
LinkNode <ElemType> *p1;
LinkNode<ElemType> *p2;
for(;p0!=0&&p0->next!=0;p0=p0->next)
{
for(p2=p0,p1= p0->next;p1!=0;)//这里有改变
{
if(p0->data==p1->data)
{
LinkNode <ElemType>*p3=p1;
p1=p1->next;
p2->next=p1;
delete p3;
if(p1==0)
{
break;
}
continue;//这里有改变
}
p2=p1,p1= p1->next;//这里有改变
}
}
}
};
改完这里就大功告成了 ╮(~▽~)╭