-
循环链表与普通链表的区别就是将链表的尾节点的下一个指向链表的头节点,同时判断遍历链表结束的条件也会改变,这里可以采用do while的形式进行遍历,具体实现可以参考下面的Output函数。
-
删除时要考虑两种情况,一是删除中间节点和尾节点,第二个是删除头节点,这里只细说一下删除头节点的情况,删除头节点时需将链表尾节点的指针指向头节点的下一个,然后释放头节点,并将头节点置空
-
详细代码如下:共有两个类,一个是node类,一个是list类
#include <iostream>
#include <conio.h>
using namespace std;
template <class T>
class Node
{
public:
void set_next(Node<T>* p) { next = p; }
T& get_data() { return data; }
void set_data(T _data) { data = _data; }
Node<T>* get_next() { return next; }
private :
T data;
Node<T>* next;
};
template <class T>
class List
{
public:
List() { head = new Node<T>; head->set_next(NULL); lenth = 0; }
void set_lenth(int _lenth) { lenth = _lenth; }
int get_lenth() { return lenth; }
Node<T>* get_head() { return head; }
bool Check(T& data)
{
Node<T>* temp = head->get_next(); // 临时变量,作为输入数据查重的指针
if (lenth >= 1)
{
while (temp) // 因此时表尾并未连上头节点,说以可用temp = NULL 来结束循环
{
if (temp->get_data() == data)
{
cout << "已有此数据!\n";
--lenth; // 链表长度复位
return true;
}
temp = temp->get_next();
}
}
delete temp;
temp = NULL;
return false;
}
void Add(int n) // 将head作为一个媒介,指向循环链表的第一个头节点,head本身不存放数据,只存放lenth
{
Node<T>* p = head; // p指向表尾,链接新节点
Node<T>* q = NULL; // 加入表尾的新节点
T data; // 临时记录data;
for (int i = 1; i <= n; i++, lenth++)
{
q = new Node<T>;
cin >> data;
if (Check(data) == false)
{
q->set_data(data);
q->set_next(NULL); // 此时添加还未结束,先将尾节点的下一个赋空,遍历链表
p->set_next(q);
p = q;
cout << "添加成功!\n";
}
}
q->set_next(head->get_next()); //添加结束后 将表尾指向表头,形成循环
}
void Delete(int n)
{
if (n == 1) // 判断是否删除的是头节点
{
Node<T>* temp = head->get_next();// 用temp记录头节点
Node<T>* p = head->get_next(); // 用p记录尾节点
do
{
p = p->get_next();
} while (p->get_next() != head->get_next());
head->set_next(temp->get_next());// 更换头节点
p->set_next(temp->get_next()); // 将尾节点指向新的头节点
delete temp;
temp = NULL;
lenth--;
cout << "删除成功!\n";
system("pause");
return;
}
Node<T>* p = head; // 用p记录要删除的节点上一个节点
for (int i = 1; i < n; i++)
{
p = p->get_next();
}
Node<T>* temp = p->get_next(); // 用temp记录要删除的节点
p->set_next(temp->get_next()); // 删除节点
delete temp;
temp = NULL;
lenth--;
cout << "删除成功!\n";
system("pause");
}
void Modify(int n)
{
Node<T>* p = head;
for (int i = 1; i <= n; i++)
{
p = p->get_next();
}
cin >> p->get_data();
cout << "修改成功!\n";
system("pause");
}
void Seek(int n)
{
Node<T>* p = head;
for (int i = 1; i <= n; i++)
{
p = p->get_next();
}
cout << p->get_data();
}
void Output(Node<T>* p)
{
do
{
cout << p->get_data();
p = p->get_next();
} while (p != head->get_next());
system("pause");
}
private:
Node<T>* head;
int lenth;
};
int main()
{
List<int> list;
char m[10]; // 将要创建链表的个数变为字符串类型,防止输入字符链表创建失败
int n;
while (1)
{
system("cls");
cout << "\n\n";
printf(" 管理员页面\n");
printf(" **************************************************\n");
printf(" ** 1.增 加 货 物 信 息 **\n");
printf(" ** **\n");
printf(" ** 2.删 除 货 物 信 息 **\n");
printf(" ** **\n");
printf(" ** 3.浏 览 货 物 信 息 **\n");
printf(" ** **\n");
printf(" ** 4.修 改 货 物 信 息 **\n");
printf(" ** **\n");
printf(" ** 5.查 找 货 物 信 息 **\n");
printf(" ** **\n");
printf(" ** 6.退 出 **\n");
printf(" **************************************************\n");
printf("请按键选择:");
switch (_getch())
{
case '1':
system("cls");
cout << "请输入要增加货物个数:";
while (cin >> m)
{
if (atoi(m) > 0)
{
break;
}
else
{
cout << "请输入正确的数字:";
}
}
system("cls");
list.Add(atoi(m));
system("pause");
break;
case '2':
system("cls");
cout << "请输入要删除第几个节点:";
cin >> n;
if (n > list.get_lenth() || n < 0)
{
cout << "输入数字越界!\n";
system("pause");
}
list.Delete(n);
break;
case '3':
system("cls");
if (list.get_lenth() == 0)
{
cout << "暂无数据!\n";
system("pause");
break;
}
list.Output(list.get_head()->get_next());
break;
case '4':
system("cls");
cout << "请输入要修改第几个节点:";
cin >> n;
if (n > list.get_lenth() || n < 0)
{
cout << "输入数字越界!\n";
system("pause");
}
list.Modify(n);
break;
case '5':
system("cls");
cout << "请输入要查找第几个节点:";
cin >> n;
if (n > list.get_lenth() || n < 0)
{
cout << "输入数字越界!\n";
system("pause");
}
list.Seek(n);
break;
case '6':
system("cls");
return 0;
}
}
}