链表的逆置(头插,就地逆置,递归)

数据结构实验之链表三:链表的逆置

Description
输入多个整数,以-1作为结束标志,顺序建立一个带头结点的单链表,之后对该单链表的数据进行逆置,并输出逆置后的单链表数据。
Input
输入多个整数,以-1作为结束标志。
Output
输出逆置后的单链表数据。
Sample
Input
12 56 4 6 55 15 33 62 -1
Output
62 33 15 55 6 4 56 12


链表的逆置呢一般有三种常见的方法,普通循环(头插法,就地逆置)和递归,下面的这段代码呢,是我第一次写的时候,写的,相当于,直接新建了的带头结点的链表,然后把数据倒序复制过去了。

#include
using namespace std;
struct node
{
	int data;
	struct node *next;
};
int main()
{
	struct node *head,*tail,*p,*q,*k;
	head=new struct node();
	head->next=NULL;
	tail=head;
	while(1)
	{
		p=new struct node();
		p->next=NULL;
		cin>>p->data;
		if(p->data==-1)
			break;
		tail->next=p;
		tail=p;
	}
	//——————————逆置过程——————————
	p=head->next;
	q=new struct node();		//新链表的头结点
	q->next=NULL;
	while(p)
	{
		k=new struct node();
		k->data=p->data;
		k->next=q->next;
		q->next=k;
		p=p->next;
	}
	//———————————————————————————
	for(p=q->next;p!=NULL;p=p->next)
		cout<<p->data<<" ";
	return 0;
}

下面是头插法的代码,凭空想象比较费劲,大家可以拿纸演示一下循环过程
重点是循环开始之前的这两句,顺序不能反了,循环里面就是用p进行遍历,然后用q进行插入

	p=head->next;				//重点用p指向第一个元素
	head->next=NULL;			//将头结点与后面断开,防止成环
	while(p)
	{
		q=p;					//q和p总是指向相邻的两个结点
		p=p->next;
		
		q->next=head->next;	    //这两句是标准的插入语句,将q插入到头结点后面
		head->next=q;
	}

这是就地逆置的代码块,因为指针的方向改变了;这个也是要注意强两句的顺序
就地逆置一般用于没有头指针的链表,我这里是用p指向第一个元素后,直接把head赋值为NULL;
也可以在引入一个值为NULL的变量;
就地逆置的精髓是:
head,q, p这三个是指向顺序相邻的三个结点,利用q来改变结点的指向

	p=head->next;
	head=NULL;
	while(p!=NULL)
	{
		q=p;
		p=p->next;
		
		q->next=head;		//直接改变结点的指向,指向前面的前面的结点
		head=q;
	}

下面是递归的解法:
递归总是比较难以理解的:
先遍历找到对后一个结点,然后再回溯

node* newList(node *head)
{
    if (head == NULL || head->next == NULL)
             return head;
     node *newhead = newList(head->next);
 
     head->next->next = head;
     head->next = NULL;
     return newhead;
 }

头插法和就地逆置代码将其放到第一个完整的程序的对应位置即可

你可能感兴趣的:(数据结构)