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

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

// 初始化四个链表L、M、N、H
void chushihua(LinkList &L, LinkList &M, LinkList &N, LinkList &H)   
{
	//todo list 1: 为四个链表分配头节点并初始化
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	M = (LinkList)malloc(sizeof(LNode));
	M->next = NULL;
	N = (LinkList)malloc(sizeof(LNode));
	N->next = NULL;
	H = (LinkList)malloc(sizeof(LNode));
	H->next = NULL;
	printf("链表初始化成功！\n");
}

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

// 求表长，返回L中数据元素个数
void Length(LinkList L){ 
    LNode *p;     //申请临时变量p
    p = L->next;  //p指向第一个结点(首元结点)
    int length = 0;             
	//todo list 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;
	int i;  // 循环变量声明
	for (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)    //如果p的下一个节点是NULL（即链表为空或p指向链表的最后一个节点）
	       //todo list 4: 直接插入新节点
	       L->next = q;
		else          //如果链表不为空或p不是指向链表的最后一个节点，则进入这个else块（查找新节点的插入位置） 
		{
			while (p->next != NULL && p->next->data < q->data)
			{
				//todo list 5: p指针不断往后移动 
				p = p->next;
				if (p->next == NULL)
					break;
			}
			//todo list 6: 插入*q结点 
			q->next = p->next;
			p->next = q;
		}
	}
	printf("数据插入完成！\n");
}

// 显示链表L的所有元素
void xianshi(LinkList &L)
{
	LNode *p;     //申请临时变量p     //LinkList p;
	p = L;
	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;
	p = L->next;  //todo list 7: p指针指向第一个数据节点
	
	// 初始化M和N链表
	M->next = NULL;
	N->next = NULL;
	
	LNode *m_tail = M;  // M链表的尾指针
	LNode *n_tail = N;  // N链表的尾指针
	
	while (p != NULL)
	{
		if (p->data % 2 == 0)   //找出偶数元素，用尾插法将这些偶数元素建立成一个【偶数链表】 
		{
			o = (LinkList)malloc(sizeof(LNode));
			//todo list 8: 使用尾插法插入偶数节点
			o->data = p->data;
			o->next = NULL;
			n_tail->next = o;
			n_tail = o;
		}
		else                   //找出奇数元素，用尾插法将这些奇数元素建立成一个【奇数链表】 
		{
			j = (LinkList)malloc(sizeof(LNode));
			//todo list 9: 使用尾插法插入奇数节点
			j->data = p->data;
			j->next = NULL;
			m_tail->next = j;
			m_tail = j;
		}
		//todo list 10: p指针往后移动
		p = p->next;
	}
	printf("奇数链表为：");
	xianshi(M);
	printf("偶数链表为：");
	xianshi(N);
}

// 3、合并一个递减链表：将奇数链表J和偶数链表O合并为一个新的链表H，合并时保持元素的有序性。
void hebiao(LinkList &J, LinkList &O, LinkList &H)
{
	// 先将两个链表转换为数组，然后排序，最后用头插法创建递减链表
    int data[100];  // 假设最多100个元素
    int count = 0;
    LNode *p;
    int i, j;  // 循环变量声明
    LNode *t;
    
    // 收集奇数链表的数据
    p = J->next;
    while (p != NULL) {
        data[count++] = p->data;
        p = p->next;
    }
    
    // 收集偶数链表的数据
    p = O->next;
    while (p != NULL) {
        data[count++] = p->data;
        p = p->next;
    }
    
    // 对数据进行升序排序（从小到大）- 这样头插后会变成降序
    for (i = 0; i < count - 1; i++) {
        for (j = i + 1; j < count; j++) {
            if (data[i] > data[j]) {  // 如果前一个元素大于后一个元素，交换它们
                int temp = data[i];
                data[i] = data[j];
                data[j] = temp;
            }
        }
    }
    
    // 使用头插法创建递减链表
    H->next = NULL;
    for (i = 0; i < count; i++) {
        t = (LinkList)malloc(sizeof(LNode));
        t->data = data[i];
        t->next = H->next;
        H->next = t;
    }
    
    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));

	// 初始化链表
	head->next = NULL;
	ji->next = NULL;
	ou->next = NULL;
	he->next = NULL;

	int choose = -1, n;
	printf("*********************************************\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("请输入您的选择：");
		scanf("%d", &choose);
		switch (choose)
		{
		case 1:
			chushihua(head, ji, ou, he); 
			break;
		case 2:
			printf("请输入要插入的整数个数：");
			scanf("%d", &n);
			charu_1(head, n);
			break;
		case 3:
			fenbiao(head, ji, ou); 
			break;
		case 4:
			hebiao(ji, ou, he); 
			break;
		case 5:
			printf("当前(递增)单链表内容为：");
			xianshi(head); 
			break;
		case 6:
			Length(head); 
			break;
		case 7:
			Emp(head); 
			break;
		case 0:
			printf("程序已退出，感谢使用！\n");
			exit(0); 
			break;
		default:
			printf("输入错误，请重新输入！\n"); 
			break;
		}
	}
	return 0;
}
