单链表进行快速排序
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; }
相关文章推荐
- C语言memcpy和memmove函数的理解和区别
- apache+tomcat分布式集群搭建
- iOS开发网络篇—发送GET和POST请求(使用NSURLSession)
- oracle中的decode的使用
- Makefile例子
- 数据结构:hash_map原理
- [IMX6DL]do_gettimeofday()的精度分析
- Mybatis中oracle、mysql、db2、sql server的like模糊查询
- spark.streaming.concurrentJobs参数分析
- 添加删除用户
- Asp.net Session保存到Redis: 使用 RedisSessionStateProvider
- Angluar中Controller之间通信方法
- 8种交换
- vb14
- 范范(10)
- 二叉排序树(BST)创建,删除,查找操作
- 详解JSP中的语句对象Statement操作MySQL的使用实例
- mysql登录报错提示:ERROR 1045 (28000)的解决方法
- 通过Android源代码分析startActivity()过程(下)
- 使用virtualbox设置双网卡,桥接+内部网络