排序算法总结|数组和链表实现的对比|leetcode c++

本文详细介绍了快速排序和归并排序在数组和链表中的实现,强调了两种数据结构下的关键差异。在快速排序中,通过从头尾双向进行粗排序确保元素均衡分布。数组实现时,使用两个指针寻找坑位。链表实现则需额外考虑元素不可直接访问的问题。归并排序采用自顶向下的策略,数组和链表实现各有特点,链表实现涉及子链的合并操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排序算法对比一览图

类别方法数组实现链表实现稳定适用场景
时间复杂度空间复杂度时间复杂度空间复杂度
插入排序直接插入

O(n^2)

O(1)O(n^2)O(1)在数列近乎可下降到O(n)
shell排序O(nlogn)O(1)--延续了上一思想
交换排序冒泡排序O(n^2)O(1)O(n^2)O(1) 
快速排序O(nlogn)

非递归:O(1)

递归:O(logn) ~ O(n)

O(nlogn)不考虑递归:

O(1)

改进:

1)小partition上:插入排序

2)重复元素多:头尾指针 or 三路快排

选择排序直接选择O(n^2)O(1)O(n^2)O(1) 
堆排序O(nlogn)O(1)-- 
归并排序O(nlogn)O(n)O(nlogn)O(1) 
桶排序     

 

算法详解

快速排序

一个细节:在做partition时,为什么要从头尾两个方向向中间进行粗排序?

使得分割的左右两部分元素数量更均衡。只有一个方向遍历的话,等于key的元素分布会堆积在同一边;两个方向遍历的话,判断里都覆盖(或都不覆盖)等于key的元素,就能避免堆积。

数组实现

(可直接运行)

编程心得:两个指针实际含义是 一个指向坑位,一个找新坑位。

leetcode第912题

#include <iostream>
using namespace std;
void print(int nums[], int l, int r){
    for(int i=l; i<=r; ++i){
        cout<<nums[i]<<" ";
    }
    cout<<endl;
}
void sort(int nums[], int l, int r){
    if(l>=r) return;
    int key = nums[l];
    int il = l, ir = r;
    while (il<ir) {
        while(il<ir && nums[ir]>=key){
            --ir;
        }
        if(il<ir) nums[il++] = nums[ir];
        while(il<ir && nums[il]<=key){
            ++il;
        }
        if(il<ir) nums[ir--] = nums[il];
    }
    nums[il] = key;
    sort(nums, l, il-1);
    sort(nums, il+1, r);
}

int main(int argc, const char * argv[]) {
    int nums[] = {2,4,1,3,2};
    print(nums,0,4);
    sort(nums, 0, 4);
    print(nums,0,4);
    return 0;
}

链表实现

(leetcode第148题)

点1:链表中元素无法直接访问,导致找坑不能跳着找,因此解决办法是从前向后捋,记录前小后大的分界线,把未排序中小的往分界线放。

点2:key元素的坑位最后决定,但由于链表中无法直接访问,key一旦换开就很难找到,因此排序时先不要占用key的坑位,只在最后把头部的key和分界线上小的元素位置交换。

变量含义:p用来记录分界线上小于一边的元素,q用来找未排序中需要往前调动的小于的元素。

运行结果:实现一速度和内存略少于实现二。

实现一:链表不动,子链用首尾元素来判别。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL || head->next==NULL) return head;
        sort(head, NULL);
        return head;
    }
    void sort(ListNode* head, ListNode* end){
        if(head==end || head->next == end) return;
        int key = head->val;
        ListNode *p = head, *q = head->next;
        bool isok = true;
        while(q!=end){
            if(q->val < key){
                p = p->next;
                swap(p->val, q->val);
            }
            q = q->next;
        }
        swap(p->val, head->val);
        sort(head, p);
        sort(p->next, end);
    }
    void swap(int &p, int &q){
        int tmp = q;
        q = p;
        p = tmp;
    }
};

实现二:断开链表,子链是拆成单独的链。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL || head->next==NULL) return head;
        ListNode *tmp = head->next;
        ListNode *less = new ListNode(0);
        ListNode *big = new ListNode(0);
        ListNode *i = big, *j = less;
        while(tmp!=NULL){
            if(tmp->val >= head->val){
                i->next = tmp;
                i = i->next;
            }else{
                j->next = tmp;
                j = j->next;
            }
            tmp = tmp->next;
        }
        i->next = NULL;
        j->next = NULL;
        ListNode *left = sortList(less->next);
        ListNode *right = sortList(big->next);
        if(left!=NULL){
            i = left;
            while(i->next!=NULL){
                i = i->next;
            }
            i->next = head;
        }
        head->next = right;
        return (left)?left:head;
    }
};

 

归并排序

自顶向下:不断二分,逐个合并有序子列。

数组实现

(代码可直接运行)

#include <iostream>
using namespace std;

void print(int nums[], int len){
    for(int i=0; i<len; ++i){
        cout<<nums[i]<<" ";
    }
    cout<<endl;
}

void merge(int nums[], int l, int mid, int r){
    int tmp[r-l+1];
    int itmp = 0, ir = mid+1, il = l;
    while(il<=mid && ir<=r){
        if(nums[il]<=nums[ir]){
            tmp[itmp] = nums[il++];
        }else{
            tmp[itmp] = nums[ir++];
        }
        ++itmp;
    }
    while(il<=mid){
        tmp[itmp++] = nums[il++];
    }
    while(ir<=r){
        tmp[itmp++] = nums[ir++];
    }
    itmp = 0;
    il = l;
    while(itmp<r-l+1){
        nums[il++] = tmp[itmp++];
    }
    print(nums,4);
}

void sort(int nums[], int l, int r){
    if(l>=r) return;
    int mid = (l + r) / 2;
    sort(nums, l, mid);
    sort(nums, mid+1, r);
    merge(nums, l, mid, r);
}

int main(int argc, const char * argv[]) {
    int nums[] = {4,2,1,3};
    sort(nums, 0, 3);
    print(nums, 4);
    return 0;
}

链表实现

(leetcode第148题,可直接运行)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL || head->next==NULL) return head;
        ListNode *t1 = head, *t2 = head;
        while(t2!=NULL && t2->next != NULL){
            t2 = t2->next->next;
            if(t2==NULL) break;
            t1 = t1->next;
        }
        t2 = t1->next;
        t1->next = NULL;
        ListNode* l1 = sortList(head);
        ListNode* l2 = sortList(t2);
        return merge(l1, l2);
    }
    ListNode* merge(ListNode* l1, ListNode* l2){
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;
        ListNode* node = new ListNode(0);
        ListNode *tail = node;
        while(l1!=NULL && l2!=NULL){
            if(l1->val <= l2->val){
                tail->next = l1;
                l1 = l1->next;
            }else{
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
            tail->next = NULL;
        }
        if(l1!=NULL){
            tail->next = l1;
        }
        if(l2!=NULL){
            tail->next = l2;
        }
        return node->next;
    }

};

 

参考:

1.数组实现的排序算法对比:https://blog.youkuaiyun.com/yushiyi6453/article/details/76407640

https://blog.youkuaiyun.com/wuxinyicomeon/article/details/5996675

2.链表实现对比:https://www.cnblogs.com/TenosDoIt/p/3666585.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值