链表的三种插入排序+冒泡排序

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;
    }
};

以上是关于链表的三种插入排序+冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章

java中数组的三种排序算法

python常见的三种列表排序算法分别是啥?

冒泡排序的三种实现

白话经典算法系列之一 冒泡排序的三种实现

ava对数组元素排序的三种方式

白话经典算法系列之一 冒泡排序的三种实现 转