归并排序
思路:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。
代码编写分为以下三步:
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
2)写出merge函数,即如何合并链表;
3)写出mergesort函数,实现上述步骤。
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
/*归并排序*/
ListNode* findMidddleNode(ListNode* head)//寻找链表中间节点
{
ListNode* first = head -> next;
ListNode* second = head;
while(first && first -> next)
{
first = first -> next -> next;
second = second -> next;
}
return second;
}
ListNode* mergeLists(ListNode* l1, ListNode* l2)//合并链表
{
if(!l1) return l2;
if(!l2) return l1;
ListNode* pNode = new ListNode(-1);
ListNode* head = pNode;
while(l1 && l2)
{
if(l1 -> val < l2 -> val)
{
head -> next = l1;
l1 = l1 -> next;
}
else
{
head -> next = l2;
l2 = l2 -> next;
}
head = head -> next;
}
if(!l1) head -> next = l2;
if(!l2) head -> next = l1;
return pNode -> next;
delete pNode;
}
ListNode* sortList(ListNode* head)//归并排序
{
if(!head || !(head -> next))
return head;
ListNode* middle = findMidddleNode(head);
ListNode* right = sortList(middle -> next);
middle -> next = NULL;
ListNode* left = sortList(head);
return mergeLists(left, right);
}
快速排序
思路:
1)选取第一个节点作为枢轴,然后遍历链表;
2)如果当前元素小于枢轴的元素,则采用头插法,把该位置的节点插入到链表的首位置,如果当前元素大于枢轴元素,则当前元素向后移动一位;
3)遍历一遍链表以后,最后枢轴的位置,把链表分割为两部分,前部分元素小于枢轴元素,后半部分元素大于枢轴元素;
4)分别对前半部分元素和后半部分元素进行快速排序。
代码:
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
/*快速排序*/
void partition(ListNode* first, ListNode* last)//对链表中的元素进行划分
{
if (first->next == last)
return;
ListNode* pre = first;
ListNode* cur = pre->next;
ListNode* privot = cur;
//调整链表中的元素,使小于privot值的元素在privot前边,大于privot值的元素在privot后边
while (cur->next != NULL && cur->next != last)
{
//头插法使小于privot值的元素在privot前边
if (cur->next->val < privot->val)
{
ListNode *tmp = pre->next;
pre->next = cur->next;
cur->next = cur->next->next;
pre->next->next = tmp;
}
else//使大于privot值的元素在privot后边
cur = cur->next;
}
//递归快排前半部分
partition(first, privot);
//如果有多个privot的值相同,则取最后一个pirvot
while (privot->next != last && privot->next->val == privot->val)
privot = privot->next;
//递归快排后半部分
if (privot->next != last)
partition(privot, last);
}
ListNode* sortList(ListNode* head)//快速排序
{
if (head == NULL || head->next == NULL)
return head;
ListNode *pHead = new ListNode(-1);
pHead->next = head;
partition(pHead, NULL);
return pHead->next;
}
插入排序
思路:
1)将原链表分为以newHead为头节点的已排序链表和以head为头节点的待排序链表,初始时已排序链表为空;
2)顺序遍历待排序链表中的元素,在已排序链表中找到应该插入的位置,并插入;
3)最终待排序链表为空,原链表排序完毕。
代码:
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
/*插入排序*/
ListNode *insertionSortList(ListNode* head) {
ListNode* newHead = new ListNode(-1);
while(head != NULL){
//保存head位置
ListNode* temp = head->next;
ListNode* cur = newHead;
//寻找待插入的位置
while(cur->next != NULL && cur->next->val < head->val)
cur = cur->next;
//插入
head->next = cur->next;
cur->next = head;
//恢复head
head = temp;
}
return newHead->next;
}