编写一个算法来颠倒一个链表,该链表的第一个结点由first指向。不要复制列表元素;而是重置链接和指针,使得first指向原来的最后一个结点,并且结点之间的所有链接都反向。
思路:因为题目中明确说明不能复制元素,所以通过复制来重置另外一个链表的想法被终止。我们想到,如果要改变连接的指向,又能够要使链表继续遍历,那么最少需要先遍历到几个结点呢?答案是3个。如图:(第二张是将要结束时的情况)
3个结点之后就可以对第一个连接进行反转,直到cur->next-==NULL结束,然后对最后一个特殊处理即可,详见代码。
#include <iostream>
#include <ctime>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
template <typename T>
class clist
{
public:
struct node
{
T value;
node* next;
node(T v=NULL) :value(v){}
};
node *front;
node *tail;
int size;
clist(node *f = NULL, node*t = NULL, int s = NULL) :front(f), tail(t), size(s){}
~clist()
{
if (!size)
{
node* temp = front;
node* pre = NULL;
while (temp != tail)
{
pre = temp;
temp = temp->next;
delete pre;
}
delete temp;
size = 0;
}
}
void build_list_rand(int len)
{ //创建一条任意长度的为len的链表
srand((unsigned)time(NULL));
front = new node();
front->value = rand()%100+1;
node* temp = front;
size++;
while (size<len)
{
temp->next = new node;
temp->value = rand()%100+1;
temp = temp->next;
size++;
}
tail = temp;
tail->value = rand()%100+1;
tail->next = NULL;
}
void swap(node* &a, node* &b)
{ //交换两个指针
node* temp = a;
a = b;
b = temp;
}
void clist<T>::reserve()
{ //反转函数
node* head=NULL, *mid=NULL, *follow=NULL, *temp=NULL;
if (size <= 1)
return;
else if (size == 2)
{
swap(front, tail);
front->next = tail;
tail->next = NULL;
}
else
{
swap(front, tail);
head = tail;
mid = tail->next;
follow = mid->next;
while (follow != NULL)
{
mid->next = head;
head = mid;
mid = follow;
follow = follow->next;
}
mid->next = head;
tail->next = NULL;
}
}
void display()
{ //打印整个链表和长度
node* temp = front;
while (temp != tail)
{
cout << temp->value << ' ';
temp = temp->next;
}
cout << temp->value << endl;
cout << "the size is " << size << endl;
}
};
int main()
{
clist<int> a;
int b;
cout << "请输入您要反转的链表的长度:" << endl;
cin >> b;
a.build_list_rand(b);
a.display();
a.reserve();
a.display();
return 0;
}
运行结果: