双向链表排序

#include <stdio.h>


struct Student
{
	char szName[20];
	unsigned long ulNumber;
	unsigned int uAge;
};

struct Node
{
	Student student;//其他结构体可作为结构体的成员变量
	int iScore;//学生成绩
	Node* pNext;//此结构体本身的指针可以作为自身的成员变量
	//Node pNext;// 错误!结构体本身不可以作为自身的成员变量
	Node* pPrevious;// 双向链表中的一个节点,pNext 指向此节点后一个节点
					// pPrevious 指向此节点前一个节点
};


// 因为此函数定义在 main() 函数后面了,所以要前置声明后
// 在 main() 函数里才能使用
void str_copy(char* szTo, char* szFrom);

void print_node(Node* pNode);

void print_list(Node* pHead);

void swap_node(Node* pNode, Node* qNode);


int main()
{
	Node node;// 声明一个节点,后面作为头节点
	Node* pHead = &node;// 双向链表的头节点,一般不会保存有用数据,仅使用其中的
				// pNext 指针指向链表的第一个保存有用数据的节点;
	pHead->pPrevious = NULL; // 头节点没有前向节点,置为空指针
	
	// 开始构造第一个有用节点
	Node curNode;
	char curStudentName[] = "xiaoming";//注意此处不能超过19个字符,在Student
									//结构体定义的学生姓名为20个字符,要预留出一个
									// 位置放字符串终止字符 '\0',此字符会自动添加到
									// curStudentName[] 数组中
	// 如函数中所示,复制数组时要一个元素一个元素的复制
	str_copy(curNode.student.szName, curStudentName);
	curNode.student.ulNumber = 10001;
	curNode.student.uAge = 10;
	curNode.iScore = 98;
	curNode.pPrevious = pHead; // 第一个有用节点的前置节点时头节点
	pHead->pNext = &curNode;   // 同理,头节点的后置节点为第一个有用节点

	// 下面构造第二个节点
	Node curNode2;
	char curStudentName2[] = "xiaohong";
	str_copy(curNode2.student.szName, curStudentName2);
	curNode2.student.ulNumber = 10002;
	curNode2.student.uAge = 11;
	curNode2.iScore = 96;
	curNode2.pPrevious = pHead->pNext;// 第二个节点的前置节点为第一个节点
	pHead->pNext->pNext = &curNode2;// 同理,第一个节点的后置节点为第二个节点

	//下面用循环从第二个节点开始多构造几个节点
	Node nodes[7];
	Node* pCurNode = &curNode2;
	for (int i = 0; i < 7; ++i)
	{
		char studentName[20] = "xiaogang";
		studentName[8] = 'A' + i;
		studentName[9] = '\0';//因为上一条语句覆盖了自动添加的字符串终止符
								//所以此处要手动添加
		str_copy(nodes[i].student.szName, studentName);
		nodes[i].student.ulNumber = 10003 + i;
		// 如果学号为偶数则年龄为 10 岁,否则为 11 岁
		nodes[i].student.uAge = nodes[i].student.ulNumber % 2 == 0 ? 10 : 11;
		nodes[i].iScore = 100 + 2 * i;

		nodes[i].pPrevious = pCurNode;// 此节点的前置节点为上一步循环中构造的节点
		pCurNode->pNext = &nodes[i];// 上一步循环中构造的节点的后置节点为此节点

		pCurNode = &nodes[i];// 构造完毕后,用pCurNode记录当前节点用于下一步循环
	}

	pCurNode->pNext = NULL;// 特别注意!最后一个节点的后置节点为空指针
							// 因为最后一个节点就没有后置节点了

	print_list(pHead);

	swap_node(pHead->pNext, pHead->pNext->pNext->pNext->pNext);
	printf("------------------------\n");
	print_list(pHead);

	swap_node(pHead->pNext, pHead->pNext->pNext);
	printf("------------------------\n");
	print_list(pHead);


	// 接下来用冒泡排序算法对链表里的学生进行按成绩降序排名
	// 拿到第一个学生的节点
	Node* pNode = pHead->pNext;
	// 因为 pNode 指向的学生需要和他后面的学生进行比较
	// 所以需要保证他后面还有学生
	while (pNode->pNext != NULL)
	{
		// 记录 pNode 用于循环迭代,后面交换会改变 pNode 节点
		// 所以提前记录到pPreNode
		Node* pPreNode = pNode->pPrevious;
		// 拿到 pNode 后面的节点
		Node* qNode = pNode->pNext;
		// 还没有比到最后一个学生则继续比较
		while (qNode != NULL)
		{
			// 记录下 qNode 的前置节点
			Node* qPreNode = qNode->pPrevious;

			// 就算记录了 qNode 的前置节点,后面的交换操作
			// 也有可能破坏这个前置节点,此标志用于标记破坏的
			// 情形,进行特殊处理
			bool pqFlag = false;

			// 如果后面的学生成绩高,则把他向前交换
			if (pNode->iScore < qNode->iScore)
			{
				if (qPreNode == pNode)
				{
					// qNode 的前置节点被破坏的情形就是 
					// qPreNode 与 pNode 相等时,此时交换pNode, qNode
					// 就会改变 qPreNode 的值,而此时 qPreNode == pNode 
					// 说明 pNode 正好就是 qNode 的前置节点,因此...
					pqFlag = true;
				}
				swap_node(pNode, qNode);
				pNode = pPreNode->pNext;
			}
			if (pqFlag)
			{
				// ...接上,pNode 前置节点的后置的后置就是 qNode,
				// 再后置就是 qNode 的下一个节点,进入后续循环进行比较
				qNode = pPreNode->pNext->pNext->pNext;
			}
			else
			{
				qNode = qPreNode->pNext->pNext;
			}
			
		}
		pNode = pPreNode->pNext->pNext;
	}

	printf("after being sorted:\n");
	print_list(pHead);

	return 0;
}


void str_copy(char* szTo, char* szFrom)
{
	for (int i = 0;/* 此处未用到可为空,但后面的分号不可省略 */; ++i)
	{
		szTo[i] = szFrom[i];
		if (szFrom[i] == '\0')
		{
			// 复制到最后的字符串终止字符了,跳出循环
			break;//跳出从 break 往外数的第一个循环,此处即为 for 循环
		}
	}

}


void print_node(Node* pNode)
{
	printf("Student Name: %s\n", pNode->student.szName);
	printf("Student Number: %d\n", pNode->student.ulNumber);
	printf("Student Age: %d\n", pNode->student.uAge);
	printf("Student Score: %d\n", pNode->iScore);
}

// 打印整个链表的有用数据
void print_list(Node* pHead)
{
	// 首先把第一个有用数据的指针复制给 pCurNode
	Node* pCurNode = pHead->pNext;

	//如果不是空指针,则说明未到链表结尾
	//则打印这个节点
	while (pCurNode != NULL)
	{
		print_node(pCurNode);
		pCurNode = pCurNode->pNext;
	}
}

// 在链表中交换两个节点的位置,实际上就是
// 分别交换这两个节点的前后置节点指针
void swap_node(Node* pNode, Node* qNode)
{
	// 先记录两个节点的前后置指针
	Node* pPreNode = pNode->pPrevious;
	Node* pNextNode = pNode->pNext;
	Node* qPreNode = qNode->pPrevious;
	Node* qNextNode = qNode->pNext;

	// 如果两个节点不相邻,说明两者之间有节点,
	// bNodesExist 则为 true
	bool bNodesExist = pNextNode != qNode;

	if (bNodesExist)
	{
		pNode->pNext = qNextNode;
		pNode->pPrevious = qPreNode;
		qNode->pNext = pNextNode;
		qNode->pPrevious = pPreNode;
	}
	// 如果两个节点相邻,则交换方式与不相邻不同
	else
	{
		qNode->pNext = pNode;
		qNode->pPrevious = pPreNode;
		pNode->pNext = qNextNode;
		pNode->pPrevious = qNode;
	}
	
	// 再考虑靠近头节点位置节点的前置指针,此时 pNode 和 qNode
	// 已经互换位置,此时 qNode 靠近头节点
	pPreNode->pNext = qNode;
	// 同理
	if (qNextNode != NULL)
	{
		qNextNode->pPrevious = pNode;
	}

	// 最后需要考虑两个交换节点之间的节点
	// 若两个节点之间有节点
	if (bNodesExist)
	{
		if (pNextNode != NULL)
		{
			pNextNode->pPrevious = qNode;
		}
		qPreNode->pNext = pNode;
	}
	// 若两个节点之间没有节点,则在前面交换两个节点内容
	// 已经完成了交换操作
}



----------------运行结果----------------------
Student Name: xiaoming
Student Number: 10001
Student Age: 10
Student Score: 98
Student Name: xiaohong
Student Number: 10002
Student Age: 11
Student Score: 96
Student Name: xiaogangA
Student Number: 10003
Student Age: 11
Student Score: 100
Student Name: xiaogangB
Student Number: 10004
Student Age: 10
Student Score: 102
Student Name: xiaogangC
Student Number: 10005
Student Age: 11
Student Score: 104
Student Name: xiaogangD
Student Number: 10006
Student Age: 10
Student Score: 106
Student Name: xiaogangE
Student Number: 10007
Student Age: 11
Student Score: 108
Student Name: xiaogangF
Student Number: 10008
Student Age: 10
Student Score: 110
Student Name: xiaogangG
Student Number: 10009
Student Age: 11
Student Score: 112
------------------------
Student Name: xiaogangB
Student Number: 10004
Student Age: 10
Student Score: 102
Student Name: xiaohong
Student Number: 10002
Student Age: 11
Student Score: 96
Student Name: xiaogangA
Student Number: 10003
Student Age: 11
Student Score: 100
Student Name: xiaoming
Student Number: 10001
Student Age: 10
Student Score: 98
Student Name: xiaogangC
Student Number: 10005
Student Age: 11
Student Score: 104
Student Name: xiaogangD
Student Number: 10006
Student Age: 10
Student Score: 106
Student Name: xiaogangE
Student Number: 10007
Student Age: 11
Student Score: 108
Student Name: xiaogangF
Student Number: 10008
Student Age: 10
Student Score: 110
Student Name: xiaogangG
Student Number: 10009
Student Age: 11
Student Score: 112
------------------------
Student Name: xiaohong
Student Number: 10002
Student Age: 11
Student Score: 96
Student Name: xiaogangB
Student Number: 10004
Student Age: 10
Student Score: 102
Student Name: xiaogangA
Student Number: 10003
Student Age: 11
Student Score: 100
Student Name: xiaoming
Student Number: 10001
Student Age: 10
Student Score: 98
Student Name: xiaogangC
Student Number: 10005
Student Age: 11
Student Score: 104
Student Name: xiaogangD
Student Number: 10006
Student Age: 10
Student Score: 106
Student Name: xiaogangE
Student Number: 10007
Student Age: 11
Student Score: 108
Student Name: xiaogangF
Student Number: 10008
Student Age: 10
Student Score: 110
Student Name: xiaogangG
Student Number: 10009
Student Age: 11
Student Score: 112
after being sorted:
Student Name: xiaogangG
Student Number: 10009
Student Age: 11
Student Score: 112
Student Name: xiaogangF
Student Number: 10008
Student Age: 10
Student Score: 110
Student Name: xiaogangE
Student Number: 10007
Student Age: 11
Student Score: 108
Student Name: xiaogangD
Student Number: 10006
Student Age: 10
Student Score: 106
Student Name: xiaogangC
Student Number: 10005
Student Age: 11
Student Score: 104
Student Name: xiaogangB
Student Number: 10004
Student Age: 10
Student Score: 102
Student Name: xiaogangA
Student Number: 10003
Student Age: 11
Student Score: 100
Student Name: xiaoming
Student Number: 10001
Student Age: 10
Student Score: 98
Student Name: xiaohong
Student Number: 10002
Student Age: 11
Student Score: 96
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值