原地逆转链表的多种方案 |数据结构

//原地逆转链表的多种方案
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<conio.h>

//用于链表个数
#define Max 20
typedef struct node
{
	int data;
	struct node* next;
}linklist;

//菜单显示
void Menu()
{
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                  MENU                        ■\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");
}

//逆转链表方案1 课件的办法
void Reverse_01(linklist* head)
{
	linklist* p, * pre, * r=NULL;
	p = head->next;
	pre = NULL;

	while (p)
	{
		r = p->next;
		p->next = pre;
		pre = p;
		p = r;
	}
	head->next = pre;
}

//逆转链表方案2
//递归实现
//思路:首先逆置其后面的结点,最后再将头指针指向末尾,从而使得链表整个逆转
linklist *Reverse_02(linklist* head,int n)
{
	linklist* p, * r=NULL;//r是用来接收最后一个末尾指针,使得最后后可以完成头指针指向末尾指针
	static int i=0;
	p = head->next;
	if ((p==NULL)||(p->next==NULL))
	{
		return p;
	}
	else
	{
		i++;
		r = Reverse_02(p, n);//递归部分
		p->next->next = p;
		p->next = NULL;
	}
	i--;
	if (i==0)
	{
		head->next = r;//使头指针指向末尾指针
	}
	return r;
}

//逆转链表方案3
//利用循环,但是与课件实现逆转方式有所不同
//相比课件来说不够巧妙,但是更好理解
void Reverse_03(linklist*head,int n)
{
	linklist* p, * q, * r=NULL;
	p = head->next;
	q = p->next;
	while (--n)//3223 4334 5445 5555
	{
		if (n!=1)
		{
			r = q->next;
		}
		
		q->next = p;
		p = q;
		if (n!=1)
		{
			q = r;
		}
	}
	head->next->next = NULL;//这里需要在循环后断开第一节点的next,否则会形成一个第一节点结点与第二节点的双向指针,在输出时会进入死循环
	head->next = q;
}

//逆转链表方案4
//思路:将除了头节点和第一个节点之外的多余节点遍历并将每个节点摘出来放到头节点的后面(重点是减少一个r指针的使用)
void Reverse_04(linklist *head)
{
	linklist *p = NULL;
	linklist *q = NULL;
	//传入的L是头节点
	if (head && head->next)//保证至少含有两个节点以上
	{
		p = head->next;
		q = p->next;
		p->next = NULL;
	}
	while (q)//2322 3433 4544 5 null 55
	{
		p = q;
		q = q->next;
		p->next = head->next;
		head->next = p;
	}
}

//逆转链表方案5
//与方案四有一些区别,没有先处理第一个节点
void Reverse_05(linklist *head)
{
	linklist* p, * q;
	p = head->next;
	head->next = NULL;
	while (p)//1211 2322 3433 4544 5null55
	{
		q = p;
		p = p->next;
		q->next = head->next;
		head->next = q;
	}
}


//尾插法建表(这里输入改为用随机数更为方便)
void CreateList_02(linklist* head, int n)
{
	linklist* p, * r; int i;
	srand((unsigned)time(NULL));

	p = head;
	for (i = 1; i <= n; i++)
	{
		r = (linklist*)malloc(sizeof(linklist));
		r->data = rand() % 100 + 1;//0~100
		/*scanf("%d", &r->data);*/
		p->next = r;
		p = r;
	}
	r->next = NULL;

}

//输出
void Out(linklist* head)
{
	linklist* p;
	p = head->next;
	while (p)
	{
		printf("%-6d", p->data);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	linklist* A;
	int choice_01;//操作的选择
	int n1;
	A = (linklist*)malloc(sizeof(linklist));
	printf("选择A链表生成长度:");
	scanf("%d", &n1);
	CreateList_02(A, n1);
	Out(A);
	getch();
	system("cls");
	do
	{
		Menu();
		printf("请选择你要的操作 select(1-6)\n");
		scanf("%d", &choice_01);
		switch (choice_01)
		{
		case 1:
			//方案一
			Out(A);
			printf("逆转后\n");
			Reverse_01(A);
			Out(A);
			getch();
			system("cls");
			break;
		case 2:
			//方案二
			Out(A);
			printf("逆转后\n");
			Reverse_02(A, n1);
			Out(A);
			getch();
			system("cls");
			break;
		case 3:
			//方案三
			Out(A);
			printf("逆转后\n");
			Reverse_03(A, n1);
			Out(A);
			getch();
			system("cls");
			break;
		case 4:
			//方案四
			Out(A);
			printf("逆转后\n");
			Reverse_04(A);
			Out(A);
			getch();
			system("cls");
			break;
		case 5:
			//方案五
			Out(A);
			printf("逆转后\n");
			Reverse_05(A);
			Out(A);
			getch();
			system("cls");
			break;
		case 6:break;
		default:
			printf("请不要乱输入选项!\n");
			break;
		}
	} while (choice_01 != 6);

	printf("感谢使用\n");
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值