数据结构老师老教授了,写的单链表模板很厉害,不同于网上大多数链表基于C语言实现,涉及到C++部分的就cin cout。照着老师给的模板实现了C++的单链表。算是把C++的特性用得出神入化了。
设计非递减有序的带头结点的单链表LinkList。编写程序,实现从LinkList中删除值相同的多余结点。
- 需求分析:包含题目要求,程序功能,运行方式,测试数据等
题目要求设计非递减有序单链表。
单链表要求实现删除有相同值的结点,让单链表结点中每个结点值不相同。通过运行程序,选择删除相同值后,对相同的值进行删除。通过输入不同值,有些值只输入一次,而部分值重复输入,程序对输入值时能否做到正确删除来判断程序能否正确运行。
先给关键代码,再给完整代码
单链表:
设置单链表结点结构,数据域data和指针域next,并编写相应的get和set函数。
class LNode{//单链表结点结构
private:
float data;//数据域
LNode <float> *next;//指针域
}
再设置单链表存储结构,头指针,并初始化。
class LinkList{//带头结点单链表存储结构
private:
LNode <float> *front;//头指针
public:
LinkList(){//初始化
front = new LNode <float>;
}
~LinkList(){
DestroyList();
}
删除相同值:创建后继指针,q指针和r指针指向头指针,*p指向头结点后一位,当p不为空时,循环赋值,从第一位依次对比后面数字,出现相同时,r后移,q的下一个结点赋值为r的下下个结点,即跳过相同数据结点。不相同时,继续循环,然后依次对比。第一个数据对比完成,且跳过相同数据,再从第二个非相同数据继续按上面方法对比。
void deleteSameNumber(){//删除相同值
LNode <float> *p = front ->getNext();//*p指向头结点后一位
LNode <float> *q = front;
LNode <float> *r = front;
while (p != NULL) {//当p不为空时,继续循环,从第一位依次对比后面数字
q = p;
while (q->getNext()!=NULL) {//当q不为空时,继续循环,从第一位依次对比后面数字
if(p->getData() == q->getNext()->getData()){//出现相同时
r = q->getNext();
q->setNext(r->getNext());//q的下一个结点为r的下下个结点,跳过相同数据结点。
delete r;//释放
}else {
q = q->getNext();//不相同时,继续循环。
}
}
p = p->getNext();//指向下一个结点,下一位结点的数字继续对比。
}
}
非递减排序:对链表中的值进行判断,创建两个指针,一个指针指向头结点,一个作为后继指针,当后继指针的值大于前面指针的值时,指针向后,后结点小于前结点时候交换,s链表存储p,直到后继指针结束,然后第一个指针后移,后继指针指向第一个指针后面,循环前面的步骤直至排序完成。
void sortNumber(){//非递减排序
LNode <float> *p,*s;
if(front->getNext()!=NULL){//链表非空时
LNode <float> *pre = front;//头指针
LNode <float> *q = front->getNext();//头指针后结点
if(q->getNext() != NULL){
p = q->getNext();//p为q后继
while (p != NULL){//p非空时
while (p->getData()>=q->getData()){//后结点大于前结点时
p = p->getNext();//依次向后
q = q->getNext();
}
if(p!=NULL&&p->getData()<q->getData()){//后结点小于前结点时候(此时交换)
s = p;//存储p
q->setNext(p->getNext());//q后继为p的后继
p = p->getNext();//p后移
while (s->getData()>pre->getNext()->getData()) {//当s大于头指针时
pre = pre->getNext();//头指针指向第二位
}
s->setNext(pre->getNext());//否则s换为头指针后一位
pre->setNext(s);//头指针赋值为s(交换)
pre = front;//pre重新指向头结点
}
}
}
完整代码
#include <iostream>
#include <stdlib.h>
using namespace std;
template<class E>
class LNode{//单链表结点结构
private:
float data;//数据域
LNode <float> *next;//指针域
public:
LNode(){
next = NULL;
}
LNode(float data,LNode <float> *next = NULL){
this->data = data;
this->next = next;
}
float getData() const{
return data;
}
LNode <float>* getNext() const{
return next;
}
void setData(float data){
this->data = data;
}
void setNext(LNode <float> *next){
this->next = next;
}
};
template<class E>
class LinkList{//带头结点单链表存储结构
private:
LNode <float> *front;//头指针
public:
LinkList(){//初始化
front = new LNode <float>;
}
~LinkList(){
DestroyList();
}
void DestroyList(){//销毁单链表
LNode<float> *p;
while (front != NULL) {
p = front;
front = front->getNext();
delete p;
}
}
void ClearList(){//清空单链表
if(front == NULL){
front = new LNode<float>;
return;
}
LNode <float> *p = front ->getNext();
front -> setNext(NULL);
while (p != NULL) {
LNode <float> *q = p;
p = p->getNext();
delete q;
}
}
bool ListEmpty(){//判断表空
return front->getNext();
}
int ListLength(){//求链表长度
int k = 0;
LNode <float> *p = front ->getNext();
while(p != NULL){
k++;
p = p->getNext();
}
return k;
}
float GetElem(int i){//返回链表中第i个元素的值
LNode <float> *p = front->getNext();//初始化
int j = 1;//计数器
while (p&&j<i) {
p = p->getNext();//指向下一个结点
j++;
}
if(!p||j>i)
exit(1);
return p->getData();
}
LNode <float> *LocateElem(float e){//查找
LNode <float> *p = front->getNext();//初始化
while(p != NULL){//向后扫描,知道p空
if(p->getData() == e)
return p;//查找成功返回p
p = p->getNext();//指向下一个结点
}
return p;//查找失败返回NULL
}
bool ListInsert(int i,float e){//在第i个位置插入值为e的结点
LNode <float> *p = front;//初始化
int j = 0;
while (p&&j<i-1) {
p = p->getNext();
j++;
}//查找i-1个结点,p指向该结点
if(!p||j>i-1)
return false;
p->setNext(new LNode <float>(e,p->getNext()));//结点*p的指针域指向生成新结点
return true;
}
bool ListDelete(int i){//删除第i个元素
LNode <float> *p = front;//初始化
int j = 0;
while (p&&j<i-1) {
p = p->getNext();
j++;
}//查找第i个结点
if(!(p->getNext())||j>i-1)
return false;
LNode <float> *q = p->getNext();//临时保存以备释放
p->setNext(q->getNext());//改变删除结点前驱结点指针域
delete q;//释放
return true;
}
void CreateList_H(float a[],int n){//前插法创建单链表
this ->ClearList();
LNode<float> *p;
for(int i = 0;i<n;i++){
p = new LNode <float>(a[i],front->getNext());//生成新结点p
front ->setNext(p);//新结点*p插入到头结点之后
}
}
void CreateList_R(float a[],int n){//后插法创建单链表
this->ClearList();
LNode <float> *p,*r;//r指向最后结点
r = front;//尾指针指向头结点
for(int i = 0;i<n;i++){
p = new LNode <float>(a[i]);//生成新结点*p
r->setNext(p);//新结点*p插入尾结点*r之后
r = p;//r指向新尾结点p
}
}
void print(){
LNode <float> *node = front->getNext();
while (node != NULL) {
cout<<"(";
cout<< node->getData()<<"";
node = node->getNext();
cout<<")";
}
}
void sortNumber(){//非递减排序
LNode <float> *p,*s;
if(front->getNext()!=NULL){//链表非空时
LNode <float> *pre = front;//头指针
LNode <float> *q = front->getNext();//头指针后结点
if(q->getNext() != NULL){
p = q->getNext();//p为q后继
while (p != NULL){//p非空时
while (p->getData()>=q->getData()){//后结点大于前结点时
p = p->getNext();//依次向后
q = q->getNext();
}
if(p!=NULL&&p->getData()<q->getData()){//后结点小于前结点时候(此时交换)
s = p;//存储p
q->setNext(p->getNext());//q后继为p的后继
p = p->getNext();//p后移
while (s->getData()>pre->getNext()->getData()) {//当s大于头指针时
pre = pre->getNext();//头指针指向第二位
}
s->setNext(pre->getNext());//否则s换为头指针后一位
pre->setNext(s);//头指针赋值为s(交换)
pre = front;//pre重新指向头结点
}
}
}
}
}
void sortNumberInsert(float e){//插入排序
LNode <float> *q = front;//头指针
LNode <float> *p;
for(int i = 0; q->getData()<=e && q != NULL;i++){
p = q;//前驱
q = q->getNext();
}
p->setNext(new LNode <float>(e,p->getNext()));//创建结点赋值
}
void userGuide(){//用户指引
cout<<"输入1,创建链表。"<<endl;
cout<<"输入2,清空链表。"<<endl;
cout<<"输入3,插入数据。"<<endl;
cout<<"输入4,删除指定位置数据。"<<endl;
cout<<"输入5,查找指定位置数据。"<<endl;
cout<<"输入6,打印链表。"<<endl;
cout<<"输入7,删除相同的数字。"<<endl;
}
void deleteSameNumber(){//删除相同值
LNode <float> *p = front ->getNext();//*p指向头结点后一位
LNode <float> *q = front;
LNode <float> *r = front;
while (p != NULL) {//当p不为空时,继续循环,从第一位依次对比后面数字
q = p;
while (q->getNext()!=NULL) {//当q不为空时,继续循环,从第一位依次对比后面数字
if(p->getData() == q->getNext()->getData()){//出现相同时
r = q->getNext();
q->setNext(r->getNext());//q的下一个结点为r的下下个结点,跳过相同数据结点。
delete r;//释放
}else {
q = q->getNext();//不相同时,继续循环。
}
}
p = p->getNext();//指向下一个结点,下一位结点的数字继续对比。
}
}
};
int main()
{
LinkList <float> LinkList;
int n, type,t;
float num;
do{
LinkList.userGuide();
cin>>type;
switch (type) {
case 1:{
cout<<"输入链表的数据个数:";cin>>n;
float a[n];
for(int i = 0;i<n;i++){
cout<<"输入数据("<<i+1<<"):";cin>>a[i];
}
LinkList.CreateList_R(a, n);
LinkList.sortNumber();
LinkList.print();
break;}
case 2:
LinkList.ClearList();
break;
case 3:
cout<<"输入数据:";
cin>>num;
LinkList.sortNumberInsert(num);
break;
case 4:
int position1;
cout<<"输入删除的位置:";
cin>>position1;
LinkList.ListDelete(position1);
break;
case 5:
int position2;
cout<<"输入查找的位置:";
cin>>position2;
cout<<"数据为:"<<LinkList.GetElem(position2);
break;
case 6:
LinkList.print();
break;
case 7:
LinkList.print();
cout<<endl;
cout<<"以上为删除前"<<endl;
cout<<"以下为删除后"<<endl;
LinkList.deleteSameNumber();
LinkList.print();
break;
}
cout<<"如需进行其他操作,请输入1:";
cin>>t;
}while(t == 1);
return 0;
}
测试结果
以上为数据只有两个重复时候的删除,可见删除成功,且数据排序成功。
以上为当数据有相同且相同的数据值各不相同时的删除,可见删除成功,且数据排序成功。