#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct LNode
{
	int data;			// 数据域
	struct LNode *next; // 指针域
} LNode, *LinkList;		// LinkList为指向LNode类型的指针类型

void chushihua(LinkList &L, LinkList &M, LinkList &N, LinkList &H) // 初始化四个链表L、M、N、H
{
	// 1.初始化链表，将各链表头节点的next设为NULL
	L->next = NULL;
	M->next = NULL;
	N->next = NULL;
	H->next = NULL;
	printf("链表初始化完成\n");
}

void Emp(LinkList &L) // 判断链表L是否为空表
{
	// 2.判断链表是否为空（头节点的next是否为NULL）
	if (L->next == NULL)
		printf("链表为空表。\n");
	else
		printf("链表为非空表。\n");
}

void Length(LinkList L)
{				 // 求表长，返回L中数据元素个数
	LNode *p;	 // 申请临时变量p
	p = L->next; // p指向第一个结点(首元结点)
	int length = 0;
	// 3.遍历链表统计节点数量
	while (p != NULL)
	{
		length++;
		p = p->next;
	}
	printf("链表长度为：%d\n", length);
}

// 1、建立递增有序链表：向链表L中插入n个整数，插入时保持链表的有序性（从小到大）。
void charu_1(LinkList &L, int n)
{
	LNode *q, *p;
	for (int i = 1; i <= n; i++)
	{
		p = L;								 // 在每次循环开始时，将p指向链表的头节点L
		q = (LinkList)malloc(sizeof(LNode)); // 为新的节点分配内存，并将q指向这块内存
		printf("请输入第%d个整数数的值", i);
		scanf("%d", &q->data); // 将输入的值存储在q指向的节点的data字段中
		q->next = NULL;		   // 将新节点的next指针设置为NULL，表示新节点当前不指向任何节点。

		if (p->next == NULL) // 如果链表为空，直接插入
		{
			// 4.空链表时直接插入新节点
			p->next = q;
		}
		else // 非空链表，查找插入位置
		{
			while (p->next != NULL && p->next->data < q->data)
			{
				// 5.移动p指针找到插入位置
				p = p->next;
			}
			// 6.插入新节点
			q->next = p->next;
			p->next = q;
		}
	}
}

// 显示链表L的所有元素
void xianshi(LinkList &L)
{
	LNode *p; // 申请临时变量p
	p = L;
	// 7.判断链表是否为空
	if (p->next == NULL)
	{
		printf("链表为空");
	}
	while (p->next != NULL)
	{
		printf("%4d", p->next->data);
		p = p->next;
	}
	printf("\n");
}

// 2、分解：将链表L中的元素分为奇数和偶数两个链表M和N，并分别显示它们。
void fenbiao(LinkList &L, LinkList &M, LinkList &N)
{
	LNode *j, *o, *p, *temp;
	p = L;
	while (p->next != NULL)
	{
		// 8.移动p指针到下一个节点
		temp = p->next;
		p->next = temp->next; // 提前断开原链表连接，防止遍历混乱

		if (temp->data % 2 == 0) // 偶数元素，前插法插入偶数链表
		{
			o = temp;
			// 9.前插法插入偶数链表
			o->next = N->next;
			N->next = o;
		}
		else // 奇数元素，前插法插入奇数链表
		{
			j = temp;
			// 10.前插法插入奇数链表
			j->next = M->next;
			M->next = j;
		}
	}
	printf("奇表为:");
	xianshi(M);
	printf("偶表为:");
	xianshi(N);
}

// 3、合并一个递减链表：将奇数链表J和偶数链表O合并为一个新的链表H，合并时保持元素的有序性。
void hebiao(LinkList &J, LinkList &O, LinkList &H)
{
	LNode *p, *q, *t;
	p = J->next;  // 指向奇数链表第一个元素
	q = O->next;  // 指向偶数链表第一个元素
	LNode *m = H; // 合并链表的尾指针

	while (p != NULL && q != NULL) // 奇和偶表都有数据结点
	{
		if (p->data > q->data) // 奇数大于偶数，取奇数
		{
			t = (LinkList)malloc(sizeof(LNode));
			t->data = p->data;
			t->next = NULL;
			// 11.尾插法插入合并链表
			m->next = t;
			m = t;
			p = p->next; // 移动奇数链表指针
		}
		else // 偶数大于等于奇数，取偶数
		{
			t = (LinkList)malloc(sizeof(LNode));
			t->data = q->data;
			t->next = NULL;
			// 12.尾插法插入合并链表
			m->next = t;
			m = t;
			q = q->next; // 移动偶数链表指针
		}
	}

	if (p == NULL) // 奇数链表先遍历完成，处理剩余偶数
	{
		while (q != NULL)
		{
			t = (LinkList)malloc(sizeof(LNode));
			t->data = q->data;
			t->next = NULL;
			// 13.尾插剩余偶数节点
			m->next = t;
			m = t;
			q = q->next;
		}
	}

	if (q == NULL) // 偶数链表先遍历完成，处理剩余奇数
	{
		while (p != NULL)
		{
			t = (LinkList)malloc(sizeof(LNode));
			t->data = p->data;
			t->next = NULL;
			// 14.尾插剩余奇数节点
			m->next = t;
			m = t;
			p = p->next;
		}
	}

	printf("从大到小的单链表为：");
	xianshi(H); // 显示合表H
}

int main()
{
	// 生成新结点作为头结点，用头指针分别指向各头结点
	LinkList head = (LinkList)malloc(sizeof(LNode));
	LinkList ji = (LinkList)malloc(sizeof(LNode));
	LinkList ou = (LinkList)malloc(sizeof(LNode));
	LinkList he = (LinkList)malloc(sizeof(LNode));

	int choose = -1, n;
	printf("*********************************************\n");
	printf("**********            实验一          *******\n");
	printf("*********************************************\n");
	printf("**********     1.初始化单链表         *******\n");
	printf("**********     2.建立递增链表         *******\n");
	printf("**********     3.分成奇/偶两链表      *******\n");
	printf("**********     4.合并成递减单链表     *******\n");
	printf("**********     5.显示建立的(递增)单链表整体       *******\n");
	printf("**********     6.求单链表长度         *******\n");
	printf("**********     7.判断单链表是否为空   *******\n");
	printf("**********     0.退出                 *******\n");
	printf("*********************************************\n");
	while (choose)
	{
		printf("请输入你的选择项：\n");
		scanf("%d", &choose);
		switch (choose)
		{
		case 1:
			chushihua(head, ji, ou, he);
			break;
		case 2:
			printf("请输入你要插入正整数的个数：\n");
			scanf("%d", &n);
			charu_1(head, n);
			break;
		case 3:
			fenbiao(head, ji, ou);
			break;
		case 4:
			hebiao(ji, ou, he);
			break;
		case 5:
			xianshi(head);
			break;
		case 6:
			Length(head);
			break;
		case 7:
			Emp(head);
			break;
		case 0:
			exit(0);
			break;
		}
	}
	return 0;
}
