数据结构(C++) 1-2 (循环链表)
循环链表是单链表的一种变体,和单链表的区别关键在于尾结点指针域不为NULL,而是指向头结点的指针,使数据形成一个环,从而解决一些单链表不方便解决的问题。
本以为写过单链表之后再写这个应该很快,但是在实现过程还是出现了一些小问题,看来还不太熟练。不过写过这个之后确实感觉对单链表的理解更深刻了,也提高了熟练程度。这次只写了几个函数,因为写的时候感觉这和单链表好像区别真不是特别大。
今天在测试解决约瑟夫问题的时候发现Create()函数写错了,当Locate()函数传参大于链表长度时显示出现一点问题,已改正。。顺便新增了一个拷贝构造函数,方便处理数据的时候不破坏原始数据。(5/20)
今天添加约瑟夫问题实例(5/21)
其代码如下:
#include<iostream>
using namespace std;
struct Node
{
int data;
Node* link;
Node()
{
data = 0;
link = NULL;
}
Node(int data, Node* link = NULL)
{
this->data = data;
this->link = link;
}
};
class CircleLink :public Node //循环链表的关键在于形成一个环,能"转圈"遍历,查找,etc.
{
private:
Node* first;
public:
CircleLink(); //构造函数
CircleLink(int d); //构造函数
CircleLink(CircleLink& a); //拷贝构造函数
Node* GetHead() { return first; } //获得头节点
int Lenth(); //计算长度
void Show(); //返回整个节点的值,
void Show(int i); //返回前i个值 (包含第i个)
void Create(int d = 0); //创造节点,结点在尾端生成,注意形成环
Node* Locate(int i); //定位函数,返回指针
};
CircleLink::CircleLink()
{
first = new Node;
first->link = first; //指向自己
}
CircleLink::CircleLink(int d)
{
first = new Node(d);
first->link = first;
}
CircleLink::CircleLink(CircleLink& a)
{
Node* current = a.GetHead(); //获得需要复制对象的头结点
Node* destpstr = first = new Node(current->data); //生成新对象的私有成员first
while (current->link != first)
{
current = current->link;
data = current->data;
destpstr->link = new Node(data); //生成新结点并使之成链
destpstr = destpstr->link;
}
destpstr->link = first; //使尾结点指向头结点
}
int CircleLink::Lenth()
{
int count = 1; //由于通过current与current->link比较,可想记数应从1开始
Node* current = first;
while (current->link != first)
{
count++;
current = current->link;
}
return count;
}
void CircleLink::Show()
{
Node* current = first;
while (current->link != first) //current到达尾部结束循环但未能输出尾结点的值
{
cout << current->data << ' ';
current = current->link;
}
cout << current->data << endl; //输出尾结点的值
}
void CircleLink::Show(int i)
{
int count = 0;
Node* current = first;
while (count++ < i)
{
cout << current->data << ' ';
current = current->link;
}
cout << endl;
if (i > this->Lenth()) //如果显示超过循环链表长度,显示循环次数
{
cout << "it circled " << i / this->Lenth() << ' ';
if (i / this->Lenth() == 1)
cout << "time !" << endl;
else
cout << "times !" << endl;
}
}
void CircleLink::Create(int d)
{
Node* newnode = new Node(d);
if (newnode == NULL)
{
cerr << "error when creating a new node !" << endl;
exit(1);
}
Node* current = first;
while (current->link != first) //找到last节点
{
current = current->link;
}
newnode->link = current->link;
current->link = newnode;
}
Node* CircleLink::Locate(int i)
{
if (i < 0)
{
cerr << "error when locating,because of wrong parameter !" << endl;
exit(1);
}
int count = 0;
Node* current = first;
while (count++ < i)
{
current = current->link;
}
if (i > this->Lenth()) //如果超过列表长度,显示循环次数和位置
{
int times = i/ this->Lenth();
int remainder = i % this->Lenth();
cout << "it circled " << times << ' ';
if (times == 1)
cout << "time , ";
else
cout << "times , ";
cout << "and its position is in " << remainder << endl;
}
return current;
}
int main() //简单测试
{
CircleLink* a = new CircleLink;
cout << "a->Lenth(): " << a->Lenth() << endl;
Node* b = new Node(1);
Node* c = new Node(2);
a->GetHead()->link = b; //测试GetHead()函数
b->link = c;
c->link = a->GetHead();
cout << "主函数创建两个结点," << "a->Lenth():" << a->Lenth() << endl;
cout << "显示列表数据: "; a->Show(); //测试Show()及其重载函数
cout << "显示列表前5个数据: "; a->Show(5);
cout << "测试Locate()函数,链表三个结点,测试1和4,比较地址是否一致: " << endl;
cout << a->Locate(1) << endl;
cout << a->Locate(4) << endl;
for (int i = 3; i < 5; i++) //测试Create()
{
a->Create(i);
}
cout << a->Lenth() << endl;
a->Show();
return 0;
}
运行结果如下:
在vs2019上运行:
在Dev-C++上运行:
Dev-C++中出现乱码。。这是什么情况,问题出在哪?
要是有知道原因的小伙伴还请解释一下:)
今天总算是解决约瑟夫问题了。由于我的头结点是会使用的,所以和教材上的不一样,就重新编了一个约瑟夫函数,但其实和书上的差别也不大(但是感觉代码看起来怪怪的,不过好歹弄出来的,以后再来优化),唯一的区别是在开头的一点处理和书上的不同(因为头结点。。)
代码如下:
#include<iostream>
#include"CircleLink.h" //头文件为上面的代码去掉主函数
using namespace std;
void Jos(CircleLink* a,int m) //去除每次报数的第m个人
{
if (m<0)
{
cerr<<"error !"<<endl;
exit(1);
}
int lenth = a->Lenth();
if (lenth == 1) cout<<"结果: "<< a->GetHead()->data; //如果是1个的话就直接输出
else
{
CircleLink* b = a;
Node* pre = b->Locate(m - 1);
Node* del = pre->link;
pre->link = del->link;
cout << "去除的元素是: " << del->data << endl;
delete del;
for (int i = lenth - 1; i != 1; i--)
{
for (int j = 0; j < m - 1; j++)
{
pre = pre->link;
}
del = pre->link;
pre->link = del->link;
cout << "去除的元素: " << del->data << endl;
delete del;
}
cout << "结果: " << pre->data << endl;
}
}
int main()
{
CircleLink* a = new CircleLink(1); //书上的事例,8人,每三人报数
for (int i = 2; i < 9; i++) //迭代创造结点
{
a->Create(i);
}
cout << "created a link and the elements are :" << endl;
a->Show();
Jos(a, 3);
delete a;
cout << "事例二" << endl;
CircleLink* b = new CircleLink(1); //再测试一组数据,7人,每两人报数
for (int i = 2; i < 8; i++)
{
b->Create(i);
}
Jos(b, 2);
delete b;
return 0;
}
``
运行环境是VS2019
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190522205542691.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTEyNTk3,size_16,color_FFFFFF,t_70)
直接把上面的循环链表作为头文件包含进去即可(也因此了解了一下头文件的写法),但是上面的循环链表因为是一直在改动,所以不太清楚是不是和我运行的头文件完全一样。。(应该还是一样,不一样的话到时候复习的时候直接电脑里找吧)
另外,在解决约瑟夫问题的时候老是觉得同余关系能解决,但是还是没有想出来,可能方向错了。。