您的位置:首页 > 其它

单链表进行快速排序

2016-04-14 16:30 357 查看
单链表进行快速排序:选择尾元素作为枢轴,根据枢轴值把链表划分为两部分,前半部分值小于枢轴值,后半部分值大于枢轴值,划分函数的返回值为指向排好序链表枢轴前一个元素的指针。这个指针有可能是空指针,我们需要做特殊判断。在快排函数中,我们需要对空指针做特殊处理。以下是完整版代码:
//对单向链表进行快速排序
#include<iostream>
#include<random>
using namespace std;

//链表数据结构
struct ListNode
{
int val;
ListNode *next;
};

//在链表末尾追加元素
void appendTail(ListNode **pHead, int val)
{
ListNode *pNew = new ListNode;
pNew->next = NULL;
pNew->val = val;

if (*pHead == NULL)
{
*pHead = pNew;
}
else
{
ListNode *tmp = *pHead;
while (tmp->next)
{
tmp = tmp->next;
}
tmp->next = pNew;
}
}

//正序输出链表
void show(ListNode *pHead)
{
while (pHead)
{
cout << pHead->val << " ";
pHead = pHead->next;
}
cout << endl;
}

//获得链表的尾指针
ListNode *getTail(ListNode *pHead)
{
if (pHead == NULL)
return pHead;
while (pHead->next)
{
pHead = pHead->next;
}
return pHead;
}

//对链表中的元素进行划分
ListNode * partition(ListNode *&pHead, ListNode *start,
ListNode *last)
{
ListNode *pre = NULL;
int val = last->val;
ListNode *q = start;
bool flag = true;
while (q != last)
{
if (q->val < val && flag)
{
pre = start;
swap(q->val, pre->val);
flag = false;
}
else if (q->val < val)
{
pre = pre->next;
swap(q->val, pre->val);
}
q = q->next;
}
if (flag)
{
swap(start->val, last->val);
}
else
{
swap(pre->next->val, last->val);
}
return pre;
}

//对链表进行快速排序
void quick_sort(ListNode *&pHead, ListNode *start, ListNode *last)
{
//如果链表为空,直接返回
if (pHead == NULL)
return;
//首尾指针是否相等
if (start != last)
{
//枢轴元素所在的前一个位置的指针
ListNode *pre = partition(pHead, start, last);
//判断该指针是否为空,如果为空
if (pre == NULL)
quick_sort(pHead, start->next, last);
//判断该指针是否为首元素的指针
else if (pre != start)
quick_sort(pHead, start, pre);
//判断该指针的一位置的next是否等于last
if (pre != NULL && pre->next != last)
quick_sort(pHead, pre->next->next, last);
}
}

int main()
{
ListNode *pHead = NULL;
for (int i = 0; i < 100; ++i)
{
appendTail(&pHead, rand() % 100);
}
ListNode *last = getTail(pHead);
quick_sort(pHead, pHead, last);
show(pHead);
system("pause");
return 0;
}
对随机产生的一百个数进行快排的结果如下:

用以上代码在leetcode中运行,对一组只有{1,2,3}三个数的集合,以上代码运行超时,如果数组中重复的元素很多,我们在返回枢轴位置时,如果当前枢轴位置的元素和枢轴的下一个位置的元素相等,我们可以让枢轴位置加一。一下代码在leetcode中的运行时间为320ms,虽然可以达到时间要求,但效率并不高效。代码主要特点是,交换节点中的数据域,没有指针的移动。
//获得链表的尾指针
ListNode *getTail(ListNode *pHead)
{
if (pHead == NULL)
return pHead;
while (pHead->next)
{
pHead = pHead->next;
}
return pHead;
}

//对链表中的元素进行划分
ListNode * partition(ListNode *&pHead, ListNode *start,
ListNode *last)
{
ListNode *pre = NULL;
int val = last->val;
ListNode *q = start;
bool flag = true;
while (q != last)
{
if (q->val < val && flag)
{
pre = start;
swap(q->val, pre->val);
flag = false;
}
else if (q->val < val)
{
pre = pre->next;
swap(q->val, pre->val);
}
q = q->next;
}
if (flag)
{
swap(start->val, last->val);
}
else
{
swap(pre->next->val, last->val);
}
return pre;
}

//对链表进行快速排序
void quick_sort(ListNode *&pHead, ListNode *start, ListNode *last)
{
//如果链表为空,直接返回
if (pHead == NULL)
return;
//首尾指针是否相等
if (start != last)
{
//枢轴元素所在的前一个位置的指针
ListNode *pre = partition(pHead, start, last);

//判断该指针是否为空,如果为空
if (pre == NULL)
quick_sort(pHead, start->next, last);
//判断该指针是否为首元素的指针
else if (pre != start)
quick_sort(pHead, start, pre);
//判断枢轴位置的元素是否等于枢轴下一位置的元素,如果相等则向下移动一位。
while (pre != NULL && pre->next != NULL && pre->next != last
&& pre->next->next != NULL &&
pre->next->val == pre->next->next->val)
{
pre = pre->next;
}
//判断该指针的一位置的next是否等于last
if (pre != NULL && pre->next != last)
quick_sort(pHead, pre->next->next, last);
}
}
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
ListNode *last = getTail(head);
quick_sort(head,head,last);
return head;
}
leetcode中某位大牛,移动指针,而不交换数据域,总得运行时间为56ms。思想是:选取第一个节点作为枢轴,然后遍历链表,如果当前元素小于枢轴的元素,则采用头插法,把该位置的节点插入到链表的首位置,如果当前元素大于枢轴元素,则当前元素向前移动一位。遍历一遍链表以后,最后枢轴的位置,把链表分割为两部分,前部分元素小于枢轴元素,后半部分元素大于枢轴元素。代码如下:
//对链表中的元素进行划分
void partition(ListNode *start, ListNode *last)
{
if (start->next == last)
return;
ListNode *pre = start;
ListNode *cur = pre->next;
ListNode *privot = cur;
while (cur->next != NULL && cur->next != last)
{
if (privot->val > cur->next->val)
{
ListNode *tmp = pre->next;
pre->next = cur->next;
cur->next = cur->next->next;
pre->next->next = tmp;
}
else
{
cur = cur->next;
}
}
partition(start, privot);
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(INT_MIN);
pHead->next = head;
partition(pHead, NULL);
return pHead->next;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: