单链表排序 --- 插入排序、归并排序

   1、插入排序

       借助一个结点,将有序的链表挂在这个辅助结点后面

      遍历待排序链表,将结点插入到有序链表的合适位置

      注意:每次从辅助结点开始找插入点

   2、归并排序

     分解:找中间结点mid(快慢指针),然后断开链表
               head为左边链表的头结点
               mid为右边链表的头结点
     合并:两个有序链表的合并

0 创建链表

#include<iostream>
using namespace std;
#include<vector>

struct Node
{
	int val;
	Node* next;
	Node(int x) :val(x),next(NULL) {}
};

//创建链表
Node* create()
{
	//带头结点的链表
	Node* head = new Node(0);
	Node* p = head;
	vector<int> lists = { 1,4,3,2,1 };
	for (int i = 0; i < lists.size(); i++)
	{
		Node* pNewNode = new Node(lists[i]);
		p->next = pNewNode;

		p = pNewNode;//更新p
	}
	return head;
}

//打印链表
void printL(Node* L)
{
	Node* p = L;
	while (p)
	{
		cout << p->val << " ";
		p = p->next;
	}
	cout << endl;
}

int main()
{
    //创建链表
	Node* head = create();
	printL(head->next);
    
    //插入排序
	Node* sHead = insertSort(head->next); //带头结点的链表
	printL(sHead);

    //归并排序
	Node* mHead = mergeSortList(head->next);
	printL(mHead);

	return 0;
}

1、插入排序

//插入排序
Node* insertSort(Node* head)
{
	//插入排序, 排序组  待排序组   待排序组找插入位置
	//每次从头结点开始找插入位置
	if (head == NULL || head->next == NULL)
		return head;
	Node* p = head;
	Node* helper = new Node(0); //借助一个节点,指向头节点 结果链接在helper之后
	Node* pre = NULL; //p插入点的前一个节点
	Node* temp = NULL; //每次记录p之后的节点

	while (p)
	{
		temp = p->next; //记录p的下一个节点
		pre = helper;//从头节点开始找插入点
	   //找p的插入点 升序   //找第一个q小于p的位置则插入点在pre->next前面
		while (pre->next && pre->next->val < p->val)
			pre = pre->next;

		// pre   p   pre->next
		p->next = pre->next; //插入
		pre->next = p;

		p = temp;//更新p
	}
	return helper->next;
}

  2、 归并排序

//合并两个有序链表
Node* mergeTwoLists(Node* L1, Node* L2)
{
	//检查输入条件
	if (L1 == NULL)
		return L2;
	if (L2 == NULL)
		return L1;
	if (L1 == NULL && L2 == NULL)
		return NULL;

	//链接在新链表后
	Node* retHead = new Node(-1);
	Node* retP = retHead;

	while (L1 && L2)
	{
		if (L1->val <= L2->val)
		{
			retP->next = L1;
			L1 = L1->next;
		}
		else
		{
			retP->next = L2;
			L2 = L2->next;
		}
		retP = retP->next;
	}

	//若有剩余,直接连在retP后面
	if (L1)
		retP->next = L1;
	if (L2)
		retP->next = L2;
	return retHead -> next;
}

//找链表的中间结点,快慢指针
Node* findMid(Node* head)
{
	//快慢指针 fast走两步 slow走一步
	//fast走到尾部,slow恰好走到中间
	Node* fast = head;
	Node* slow = head;
	Node* tail = NULL; //tail尾部需要断开链表
	while (fast  && fast->next)
	{
		tail = slow;
		fast = fast->next->next;
		slow = slow->next;
	}
	//要断开链表
	tail->next = NULL;
	return slow;

}

//归并排序,将链表分解,直到分解为2个结点  然后两两合并
Node* mergeSortList(Node* head)
{
	//检查输入条件 处理含0或1个结点的链表
	if (head == NULL || head->next == NULL)
		return head;
	//分解  找中间mid结点,然后断开链表
	Node* mid = findMid(head);
	//两两合并
	Node* L1 = mergeSortList(head); //左边链表头结点为head
	Node* L2 = mergeSortList(mid); //右边链表头结点为mid
	return mergeTwoLists(L1,L2);
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值