链表的三种插入排序+冒泡排序
Posted C_YCBX Py_YYDS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表的三种插入排序+冒泡排序相关的知识,希望对你有一定的参考价值。
不改变结点位置的插入排序
结合数组的实现方式,唯一的不同在于从前往后遍历,但是这种插入排序对链表来说还是太慢了。
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if(!head||!head->next)
return head;
ListNode* cur = head->next;
ListNode* pre = head;
while(cur){
while(pre!=cur){
if(pre->val>cur->val)
swap(pre->val,cur->val);
pre = pre->next;
}
pre = head;
cur = cur->next;
}
return head;
}
};
通过新的newHead(存储已经排好序的元素)实现结点插入方式
这个会比之前的插入排序再快上一些,因为一旦寻找到位置,就能插入,无需再继续遍历了。
class Solution {
public:
//由于用的直接改变结点位置的关系,操作的是指针,所以原先的head头节点位置肯定会发生改变。
ListNode* insertionSortList(ListNode* head) {
if(!head||!head->next)return head;
//创建一个新的表,用于保存已经插入好的结点
ListNode* newHead = new ListNode;
ListNode* cur = head;
ListNode* pre = newHead;
while(cur){
//防止cur插入到正确位置后产生断链(因一旦cur被插入,则无法通过cur寻找下一个结点)
ListNode* p = cur->next;
//寻找正确插入位置,防止为首个位置不好操作所以才准备了头节点,每次比较pre的next位置值的关系,一旦跳出循环说明cur的正确位置在pre处。
while(pre->next&&pre->next->val<cur->val){
pre = pre->next;
}//开始将cur插入到pre的后面,由于cur后面的位置已经提前做好了备份所以从它开始操作
cur->next = pre->next;
pre->next = cur;
//初始化下一轮排序的pre和cur
pre = newHead;
cur = p;
}
ListNode* res = newHead->next;
delete newHead;
return res;
}
};
通过保存已排序的最后一个元素,防止形成环,继续优化时间。
这个方法比较难想到,它能在第二种方法的基础上继续优化,只要是插入到最后的,直接能优化为O(1)
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if (head == nullptr) {
return head;
}
ListNode* dummyHead = new ListNode(0);
//将这个连了起来,相当于要在这一条链表上操作,所以需要用lastSorted代表已排序部分的最后结点(如果让dummyHead的next指针连上head而且还像法二那样,则会形成环)
dummyHead->next = head;
ListNode* lastSorted = head;
//curr表示需要插入的结点
ListNode* curr = head->next;
while (curr != nullptr) {
//利用这个最后已排序结点,明显可以直接优化很多插入到最后位置的
if (lastSorted->val <= curr->val) {
lastSorted = lastSorted->next;
} else {
//找到要插入的位置
ListNode *prev = dummyHead;
while (prev->next->val <= curr->val) {
prev = prev->next;
}//更新已排序的最后一个结点的next指针,防止curr的插入后形成环
lastSorted->next = curr->next;
curr->next = prev->next;
prev->next = curr;
}//更新下一个要插入的结点
curr = lastSorted->next;
}
return dummyHead->next;
}
};
冒泡排序实现
冒泡是基于比较的交换方法,用链表实现只需要保证两个比较位置的更新就行了。(效率比较慢)我这里还用了flag优化,也才达到第一种插入排序的时间
class Solution {
public:
//冒泡排序:由于是基于比较的值的交换,不会像插入排序那样牵扯到结点位置的改变,导致细节较多
ListNode* insertionSortList(ListNode* head) {
if (head == nullptr) {
return head;
}
ListNode* endPtr = nullptr;
ListNode* curPtr = head;
bool flag = false;
//endPtr用于表示已经冒泡的最左元素,为了防止比较元素越界,而cur和next用于表示两个比较的元素
while(curPtr!=endPtr){
ListNode* nextPtr = curPtr->next;
//这一层循环用于冒泡,每轮排好一次最大的元素
while(nextPtr!=endPtr){
if(nextPtr->val<curPtr->val){
swap(nextPtr->val,curPtr->val);
flag = true;
}
//cur和next同时向后移动一格
nextPtr = nextPtr->next;
curPtr = curPtr->next;
}//更新endPtr
if(flag){
endPtr = curPtr;
curPtr = head;}
else
break;
}
return head;
}
};
以上是关于链表的三种插入排序+冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章