Zst_001(B站)软考-数据结构笔记简

数据结构

大O表示法

image-20231001194305036


时间复杂度

image-20231001194341918


空间复杂度

image-20231001194833459


渐进符号

image-20231001201320620


递归时间复杂度和空间复杂度

image-20231001204048344

在每次递归的时间复杂度变化的情况下:

跟递归的次数相关,(展开式次数求和)

每次递归的时间复杂度求和,直到递归结束;

递归的空间复杂度:

每次递归的空间复杂度求和,直到递归结束;


主方法(渐进紧致界)

image-20231001233643819


线性结构与线性表的定义

image-20231003150938560


线性表的插入和删除

image-20231003152204859


顺序表code

顺序表的初始化init()
//顺序表的源-数组
int[] array;//数组
int arrayLength ;//表长
final int N = 10 ;//容量假设为10
void init(){
    array = new int[N];
    //初始化数组给数组赋5个值
    for (int i = 0; i < N/2; i++) {
        array[i]=i+1;//赋值为1,2,3,4,5
    }
    arrayLength = N/2;
    for (int i = 0; i < arrayLength; i++) {
        System.out.println(array[i]);
    }
}

顺序表的插入insert()
 void insert(int k,int num){
        System.out.println();
        //1,首先判断插入元素的位置是否超过数组(顺序表)的长度;
        if(k>array.length) {//如果超出数组元素的长度,这里是
            //1,先将数组扩容
            arrayLength++;
            //2,将k赋值为array.length
            k=arrayLength;
            //示例
            //1,假设要在第顺序表的三个位置,插入元素10
//        int x = 3 ;
            //2,先遍历顺序表,将从末尾的元素开始,逐个移动到后面,最后将要插入的元素插入到顺序表对应的位置
            //3,判断当插入位置为第一个位置时的情况,还是需要先将末尾的元素开始,逐个移动到后面;
            //4,判断是否插入的元素为最后一个元素,最后一个元素在插入时不需要移动数组,只需将数组扩容,并插入到最后即可

            for (int i = arrayLength; i >= k - 1; i--) {
                //先判断插入的位置,因为插入位置前面的元素不需要移动

                if (k > arrayLength) {
                    array[arrayLength - 1] = num;
                    for (int j = 0; j < arrayLength; j++) {//注意:这里遍历的是数组的容量,而不是数组的长度length
                        System.out.print(array[j] + " ");
                    }
                    return;
                }
                if (i - 1 >= 0) {//判断是否数组越界
                    array[i] = array[i - 1];
                }
            }
            array[k - 1] = num;

            for (int i = 0; i < arrayLength; i++) {//注意:这里遍历的是数组的容量,而不是数组的长度length
                System.out.print(array[i] + " ");
            }
        }
    }

顺序表的删除delete()
void delete(int k ){
    System.out.println();
    //1,先判断删除数据的位置是否越界
    if(k>=arrayLength) {
        arrayLength--;
        k=arrayLength;
        //2,先考虑是否删除的是末尾的元素->不需要移动数组
            for (int i = 0; i < arrayLength; i++) {
                System.out.print(array[i]+" ");
            }

    }
    //3,如果不是末尾数组元素,将该位置的元素删除的步骤
    //4,遍历该位置的后面的元素,将逐个元素往前移动
    if(k<arrayLength){
        for (int i = k-1; i <arrayLength-1 ; i++) {
            array[i]=array[i+1];//将后面的元素赋值给前面
        }
        arrayLength--;
        for (int i = 0; i < arrayLength; i++) {
            System.out.print(array[i]+" ");
        }
    }
}

顺序表插入或删除的时间复杂度

image-20231004113409740


顺序表查找的时间复杂度

查找-》顺序表(使用类数组)->用下表随机存取

image-20231004113719498


链表

image-20231004114415648


单链表code

结点Node
public class Node {
    int data ;//数据域
    Node next ;//指针域

    public Node() {
    }

    public Node(int data) {
        this.data = data;
    }
}

带头结点的单链表
public class HeadLinkList {
    //带头结点的单链表
    Node head ;
    //初始化单链表
    void init(){
        head = new Node();
        Node node1= new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        //将链表节点链接起来
      head.next=node1;
        node1.next=node2;
        node2.next=node3;
    }
    void printList(){
        Node p = head.next ;//用p来循环迭代list,来输出打印list中的数据域
        while (p!=null){
            System.out.print(p.data + " ");
            p=p.next;
        }
        System.out.print("\n");
    }
}

不带头结点的单链表
public class LinkList {
    Node list ;
    //初始化单链表
    void init(){
        Node node1= new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        //将链表节点链接起来
        list=node1;
        node1.next=node2;
        node2.next=node3;

    }
    void printList(){
        Node p = list ;//用p来循环迭代list,来输出打印list中的数据域
        while (p!=null){
            System.out.print(p.data + " ");
            p=p.next;
        }
        System.out.print("\n");
    }
}

带头结点的单链表的插入
 boolean insert(int k ,Node node){
//        //带头结点的单链表
//        Node head ;
//        //插入时遍历链表的位置
//        int i = 0 ;//表示第一个节点,这里是指头结点
        //先判断插入节点位置是否越界
        if(k<1){return  false;}
        //在第k个位置之前插入新的结点node

        //因为结点之间是链接起来的,不想数组可以随机存取,需要循环遍历链表才能找到需要插入节点的前后位置

        Node p = head;//用p来循环迭代list
        while (i<k-1&&p!=null){//注:p!=null是为了防止链表越界
            i++;
            p=p.next;//遍历找到要插入节点位置的前一个节点
        }
        if(p==null){return false;}//这里是再次判断,遍历后的结点是否为空
        node.next = p.next ;//这里是将插入节点的后继赋值为迭代后插入位置前的(后继位置的next的结点)
        p.next = node ;//将插入节点位置前的next的结点赋值为node,即是插入位置前的结点的后继为当前插入节点
        return  true ;

    }

带头结点的单链表插入当表头存储的是链表长度时
 boolean insert(int k ,Node node){
//        //带头结点的单链表
//        Node head ;
//        //插入时遍历链表的位置
//        int i = 0 ;//表示第一个节点,这里是指头结点
        //先判断插入节点位置是否越界
        if(k<1||k>head.data+1){return  false;}
        //在第k个位置之前插入新的结点node

        //因为结点之间是链接起来的,不想数组可以随机存取,需要循环遍历链表才能找到需要插入节点的前后位置
        int i = 0 ;//表示第一个节点,这里是指头结点
        Node p = head;//用p来循环迭代list
        while (i<k-1){//注:p!=null是为了防止链表越界
            i++;
            p=p.next;//遍历找到要插入节点位置的前一个节点
        }
        if(p==null){return false;}//这里是再次判断,遍历后的结点是否为空
        node.next = p.next ;//这里是将插入节点的后继赋值为迭代后插入位置前的(后继位置的next的结点)
        p.next = node ;//将插入节点位置前的next的结点赋值为node,即是插入位置前的结点的后继为当前插入节点
        head.data ++;
        return  true ;

    }

不带头结点的单链表的插入
 boolean insert(int k ,Node node){
       //不带头结点的插入,
       //1,在第k个位置前插入
       //2,需要找到第k个位置前的结点所在的位置,即找到第k个位置前所在的结点
       //3,考虑特殊情况,当插入节点的位置为负数,或插入节点的位置超过单链表的长度时
        //4,考虑特殊情况,当插入节点的位置为第一个节点时,无法找到插入节点的前一个节点的位置即k-1=0(当前节点在没有头结点的单链表中不存在)
        //定义一个迭代结点,来代表链表节点中的位置
        Node p = list ;//将第一个节点赋值给p
        int i = 1;//代表第一个节点的位置
        if(k==1){
            node.next=list;//插入节点的后继结点为以前链表的第一个节点
           list=node;//将新链表的第一个节点赋值给node
            return true;
        }
        if(k<1)return false ;
        while (i<k-1&&p!=null){
            //当p不为空时迭代p,找到插入节点前的结点,k-1代表插入节点前的结点所在的位置
            p=p.next;
            i++;
        }
        if(p==null)return false;//判断插入节点前的位置是否右越界
        //假设为下列这样插入
        node.next=p.next;//插入接电的下一个位置为,找到插入节点位置的前一个节点的后继结点
        p.next=node;//success//找到插入节点位置的前一个节点的后继结点(赋值)为插入节点
//        //如果为这样
//        p.next=node;
//        node.next=p.next;//这句话如果执行前一段代码翻译->node.next=node//error
        return true;

    }

单链表插入时间复杂度

image-20231005163746304


带头节点和不带头结点的单链表删除Code
带头节点的delete()Code
boolean delete(int k ){
    //删除第k个节点
    //1,先判断删除节点的位置是否合法
    //2,遍历整个单链表找到删除节点的位置
    int i = 0 ;//这个代表头结点的位置,用来遍历整个链表
    Node p = head ;//迭代单链表
    Node s ;
    if(k<1||k>head.data){
        //head.data代表单链表的长度
        return false;
    }
    while (i<k-1){
        i++;
        p=p.next;
    }
    if (p==null)return false;
    s=p.next;
    p.next=s.next;
    return true;

}


不带头节点的delete()Code
boolean delete(int k ){
    //删除第k个节点
    //1,先判断删除节点的位置是否合法
    //2,遍历整个单链表找到删除节点的位置
    int i = 1 ;//这个代表头结点的位置,用来遍历整个链表
    Node p = list ;//迭代单链表
    Node s ;
    if(k<1){
        //head.data代表单链表的长度
        return false;
    }
    if(k==1){
        list=list.next;//删除第一个节点,将第一个节点的后继赋值给第一个节点
    }
    while (i<k-1&&p!=null){
        //因为不带头结点的单链表在删除第一个节点(k=1)和第二个节点时(k=2)
        //i<k-1都不成立
        //无法删除第一个节点
        i++;
        p=p.next;
    }
    if (p==null)return false;
    s=p.next;
    p.next=s.next;
    return true;

}

单链表删除及时间复杂度

image-20231005171153931


单链表查找及时间复杂度

image-20231005171555791


单链表获取第k个节点Code
Node GetNode(int k ){
    //获取第k个节点
    if(k<0||k>head.data)return null;
    int i = 1 ;//不获取头结点,从第一个节点开始遍历
    Node p = head.next;
    while (i<k){
        i++;
        p= p.next;
    }
    return p;
}

循环链表

循环链表与带头结点单链表的区别

head.next=head;

循环链表没有空的情况,在遍历时判断当是否为头结点时即一圈遍历完成;

尾指针tail(便于尾部插入)

image-20231005173904086


双链表

结点中多一个属性pre,即一个节点有三个属性,(data,pre,next)

image-20231005174531788


顺序栈

类似顺序表->即数组[数组头为栈底,数组尾为栈顶]

特性:先进后出,只在栈顶插入删除

image-20231005202934880


链栈

image-20231005203530212


共享栈(顺序存储)

top1移动

image-20231005210016530


image-20231005210052988

top2移动


top1和top2同时移动直到栈的空间用完

image-20231005210216026


队列

队的顺序存储结构

image-20231005232107694


循环队列

image-20231005232302598


队列的链式存储

image-20231006121030606


双端队列

image-20231006121248938


image-20231006143908294


串的模式匹配

朴素匹配

image-20231006150642724


*手算next数组

image-20231006151548751


KMP模式匹配

使用next数组值,前后缀相等,来匹配下一个位置,来移动模式串的下表,继而减少移动主串的回退,、。

了解代码

image-20231006152338830


一维数组

image-20231006155623683


二维数组

按行优先

image-20231006160411225


按列优先

image-20231006160837071


image-20231006161131658

当行和列相等时,按行存储和按列存储偏移量相等;


矩阵

对称矩阵

下三角区域i>j;行下标>列下标

对角线i=j;行下标=列下标

上三角区域i<j;行下标<列下标

下图为按行存储(下三角区域加对角线)或(上三角区域加对角线)a[i] [j] (矩阵中的元素位置)=a[k](按一维数组存储的位置)

image-20231006164547185


三对角矩阵

image-20231006172356818


A[i] [j] = A[k]<->稀疏矩阵中的元素按一维数组存储的方式,各元素对应的一维数组的元素;

image-20231006172330574


2i+j+1推导过程:

这里有个问题?

如图最大是A[4] [4] 首尾元素个数都为2,中间部分元素个数为3;

当扩大时首尾元素个数是否会扩大?中间部分元素个数是否会扩大呢?


以A[2] [3] 定位,找前面有多少个元素;

*除了第一行是两个元素外,其他行都是三个元素,

A[i] [j] 先按(ix3-1)即是都按每行3个元素计算,最后减去一个(即是第一行只有两个元素);

*再看A[i] [j] 这行前面有多少个元素;

前面两个 A[2] [3] -> j-1 = 2 (满足条件);但是 A[1] [2] -> j-1 = 1(不满足条件)

*根据A[i] [j] 这行 -> 示例:A[2] [3] 这行的排位

A[2] [1] ,A[2] [2] ,A[2] [3] ->他们这三个元素按这行从左往右分别对应,第一个即该行元素1 A[2] [1] ,第二个即该行元素2 A[2] [2] ,第三个即该行元素3 A[2] [3] 。除第一行每行的排位顺序都一致,都满足每行3个元素的 j-i 从左往右 依次为

-1 , 0 ,1 ;让他们按1,2,3排位则需要将 j-i+2 ;

所以三对角矩阵中元素对应一维矩阵中元素的公式:

a[i] [j] = a[ix3-1+j-i+2] 即 a[i] [j] = a[2i+j+1] ;


image-20231006172527048


稀疏矩阵

image-20231006175240869

三元组顺序表,十字链表是对稀疏矩阵的压缩存储方式;


树的定义

image-20231006225455751


树的基本概念

度为m的树?

该树中结点的度数的max=度为max的数;

即该树中结点的度数的max=度为m的树;

m次树=度为m的数;

image-20231006230000323


树的性质

树的节点总数

树的结点总数=树中所有结点的度数之和加1(加1即加上根节点);

image-20231006230549325


度为m的树中第i层的结点总数

image-20231006231623584


**高度为h,度为m的树中至多的结点总数/ **
具有n个节点,度为m的树的最小高度

当结点的个数限制为n时,每层的结点的度都为m时,树的高度压缩最小;

公式转换

image-20231006233135752


二叉树

二叉树的定义

image-20231007083740394

二叉树的度恒定为2(只有左子树和右子树);


二叉树的性质

image-20231007084559532

注意:第i层二叉树结点的个数; 高度为h的二叉树的至多节点个数的公式;

二者区别:公式推导?

第i层二叉树结点的个数-第一层为一个,指数为0;

高度为h的二叉树的至多节点个数的公式,等比为2的求和公式推导;

二叉树中叶子结点与度为2的节点的关系

N0=N2+1;


满二叉树;完全二叉树;非完全二叉树;

image-20231007085942630

满二叉树:每层结点没有空缺(每个结点度都为2),都为满;

完全二叉树:除了最后一层,前面每层结点都为满(每个结点度都为2),最后一层结点必须从左叶子至右子树,(最后一层不为满);

非完全二叉树:

除了最后一层,前面每层结点都为满(每个结点度都为2),最后一层结点非必须从左叶子至右子树,(最后一层不为满);


具有n个节点完全二叉树的高度

image-20231007090958612


满二叉树求层次(高度)

image-20231007093336206

[log]向下取整;

注意满二叉树求节点所在层次的公式:(+1->根节点?)


具有n个节点,求二叉树的种类(卡特兰数)

image-20231007114441395


二叉树顺序存储

image-20231007142550399

在最坏的情况下,一个深度为k且只有k个结点的二叉树(单枝树-除了叶子节点外,其余节点度都为1的树)需要的存储单元?


二叉树链式存储

image-20231007143918733


二叉链表-一对多(指针域中(存储左子树的根和右子树的根));

二叉链表n个结点的空指针域?

n个结点->2n个指针域(即存储左子树的根和右子树的根);

n个结点->n-1个有效指针域(-1即是减去根节点) ->n-1个分支(即是n-1个孩子结点);

二叉链表空指针域=总指针域-有效指针域 = n +1 ;


image-20231007145244312


三叉链表-一对多(指针域中(存储左子树的根和右子树的根,父结点的信息));

三叉链表n个结点的空指针域?

n个结点->3n个指针域(即存储左子树的根和右子树的根,父结点的信息);

n个结点->n-1个子树有效指针域(-1即是减去根节点) ->n-1个分支(即是n-1个孩子结点);n-1个父节点有效指针域(一个节点即是儿子也是父亲)

三叉链表空指针域=总指针域-有效指针域 = n +2 ;


二叉树的遍历

先序遍历

image-20231007231044719


中序遍历

image-20231007231659366


后序遍历

image-20231007232302843


层次遍历

image-20231007232603982


根据序列构造二叉树
先序中序构造二叉树

image-20231007233707529


中序后序构造二叉树

image-20231008084131073


中序层序构造二叉树

image-20231008084538636


平衡二叉树

image-20231008094516934

注意:左右子树的高度差,依次往下


二叉排序树

二叉排序树定义

image-20231008095605766


二叉排序树的构造

image-20231008105045414


最优二叉树

image-20231008154758656

什么是最优二叉树或叫做哈夫曼树?

pind.com解惑:

哈夫曼树(Huffman Tree),也称为最优二叉树,是一种特殊的二叉树,它的特性是树的带权路径长度达到最小zhuanlan.zhihu.com

首先,来解释一下哈夫曼树中的几个关键概念:

  • 路径和路径长度:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1zhuanlan.zhihu.com

  • 节点的权和带权路径长度:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积zhuanlan.zhihu.com

  • 树的带权路径长度:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPLzhuanlan.zhihu.com

构造哈夫曼树的步骤如下:

  1. 将待构造的哈夫曼树的n个权值看作是有n棵树的森林(每棵树仅有一个结点);
  2. 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
  3. 从森林中删除选取的两棵树,并将新树加入森林;
  4. 重复2、3步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树zhuanlan.zhihu.com

构造哈夫曼树的目标就是要使得这个树的带权路径长度最小。为了达到这个目标,在构造过程中,根据贪心算法的原则,每次都选择两个权值最小的节点进行合并,合并后的新节点的权值是这两个节点权值的和zhuanlan.zhihu.com

哈夫曼树的一个重要应用是哈夫曼编码,它是一种有效的编码方法,用于数据的压缩和解压缩。在哈夫曼编码中,使用频率高的字符编码长度短,使用频率低的字符编码长度长,这样可以最小化整个消息的编码长度zhuanlan.zhihu.com

什么是权值?

n个权值=n个叶子结点

pind.com解惑:

在最优二叉树(也称为哈夫曼树)中,权值(权重)是指树中节点所赋予的数值。这个数值通常有特定的含义,比如在哈夫曼编码中,字符的出现频率就是字符的权重。权值越大的节点在哈夫曼树中离根节点越近,这样可以保证权值大的节点的路径长度更短,从而最小化整棵树的带权路径长度

树的带权路径长度-是从树根到每一个叶子之间的路径长度之和.

结点的带权路径长度-为从该结点到树根之间的路径长度与该结点权值的乘积;

树的带权路径长度=树种所有叶子结点的带权路径长度之和 记为WPL;


构造最优二叉树(哈夫曼树)

image-20231008173152500


哈夫曼编码

image-20231008190205313


压缩比

image-20231008190648494


线索二叉树

线索二叉数在存储结构上类型(二叉链式存储)->未存储左子树或右子树的指针域存储它的中序遍历的顺序中的前驱或后继;

任意一个二叉树都可以是线索二叉树

image-20231008225921457


图的定义

image-20231009083707190

图中

数据元素用顶点表示;

数据元素之间的关系用边表示;边是两顶点之间的直接关系(不是路径)


有向图和无向图

image-20231009084331162


完全图

无向完全图

n个顶点的无向完全图的边数

image-20231009084752477


有向完全图

n个顶点的有向完全图的边数

image-20231009085107581


顶点的度

顶点的度是指关于该顶点的边数;

有向图中:

指出去的为出度;

指向该顶点的度为入度;

不论是无向图或有向图,总度数与边数的关系;

总度数=2*(边数);

image-20231009085751060


路径

路径长度=路径上边或弧的数目;

image-20231009090238432


连通图与强连通图

连通图->任意两个顶点之间有路径能从一个顶点达到另一个顶点;

无向连通图

image-20231009091643941

n个顶点最少n-1条边构成无向连通图;

最多(等差数列求和):(n-1)*n/2条边;


强连通图

强连通图最少为一圈闭环,即可实现任意两个顶点都是连通的;即n个顶点最少边数为n,构成强连通图;

最多就是除自己以外都和其他顶点有方向连接

边数为n(n-1);

image-20231009091545928


邻接矩阵

image-20231009094340053


邻接链表

image-20231009095315218


稠密图和稀疏图

image-20231009095639004


示例:

image-20231011112504619


空间利用率邻接表,邻接矩阵

image-20231009103452868


图的遍历

image-20231009105054646


深度优先遍历(DFS)

image-20231009113741777

核心:回溯递归;

访问图中所有结点,如果还未访问完(就回溯到上一结点看是否有路子)->直到遍历一遍图中所有结点;类似栈(先进后出)


深度优先的时间复杂度

深度优先的时间复杂度是跟图的存储结构有关;

邻接矩阵nxn遍历完(最多的情况);->深度优先遍历邻接矩阵的时间复杂度o(nxn);

最少的情况是o(n);

邻接链表结点遍历完->遍历所有结点的邻接点o(e)->遍历完所有结点o(n);

所以深度优先遍历邻接链表的时间复杂度为o(n+e);

image-20231009114440176


广度优先搜索遍历(BFS)

广度优先搜索遍历:

先将第一个结点的邻接结点访问完,再访问邻接结点的邻接结点;直到访问完一遍图中所有结点;类似队列(先进先出)

广度优先搜索遍历的时间复杂度

image-20231009115927569


image-20231009104709088


拓扑排序

AOV网(有向无环图)

如果出现有向环,意味着活动必须以自身任务的完成为先绝条件,即(出现既是前驱又是后继的情况)->产生矛盾效应;

image-20231009140312566


拓扑排序及其算法(拓扑排序序列)

image-20231009141639726


查找

image-20231009143705270


平均查找长度

image-20231009144626561


顺序查找

image-20231009145130823


折半查找(二分查找)

image-20231009222029406


![image-20231009222710921](https://img-blog.csdnimg.cn/img_convert/c90a4950218c8d1f51429ac44a8ecafb.png)

image-20231009222750556


image-20231009222830549

平均查找长度


哈希表

哈希表的定义

image-20231009234122834


哈希函数构造与冲突处理(线性开放地址法)

image-20231009235632248


image-20231009235452577


冲突处理和装填因子

冲突处理方法(二次探测再散列)

image-20231010084513407


链地址法

image-20231010084301541


哈希表的查找

image-20231010084152392


小顶堆与大顶堆

image-20231010093101594


小顶堆大顶堆的构造

对二叉树(调整为新堆 ),从下往上按照小顶堆或大顶堆的规则交换元素的位置,最后回溯看整体是否满足小顶堆或大顶堆的规则;

image-20231010094059907


排序

基本概念

image-20231010100314305


直接插入排序

从前往后遍历,如果是需要最后是升序;后面数值大于前面数值就不交换,否则就交换位置,交换位置后还需要往前比较,看是否小于前面位置的数值,如果小于重复交换;

示例要求升序(最小比较次数,原序列为升序时)

image-20231010111037110


直接插入排序的时间复杂度

image-20231010103521746


希尔排序

image-20231010104117476


希尔排序的时间复杂度

image-20231010104236121


计数排序

序列里面数值只有1-9的情况;记录个数(序已排好从1-9);

image-20231010105258622


image-20231010105408324


简单选择排序

简单选择排序(不稳定,归位)

image-20231010134329540


简单选择排序的时间复杂度

image-20231010134536431


堆排序

归位,确定位置

image-20231010134902934


堆排序的时间复杂度

image-20231010135041256


冒泡排序

image-20231010140557138


快速排序

第一个位置为a[1]=privot

先从后往前j迭代找小于privot的数值元素,将该元素赋值给i位置

然后从前往后找大于privot的数值元素,将该元素赋值给j位置

最后a[i]=privot;重复以上操作直到(i==j)推出循环;

image-20231010142703886


快速排序的时间复杂度

当原序列位有序时快排序的时间复杂度最坏;(因为快排序第一次为从后往前找最小的,如果原序列为有序就会遍历完整个序列,然后将序列划分为1|2 ,3…,n-1),再遍历后面时又依次递归;

image-20231010142426151


快速排序(取尾),(取中间)

image-20231010142834017


快速排序的平均空间复杂度,最好或最坏的时间复杂度

image-20231010145457942


归并排序

归并排序分组的规则

www.pind.com解惑:

归并排序是一种基于归并操作的有效稳定排序算法,它使用了分治法(Divide and Conquer)的思想。归并排序的基本步骤包括分割、排序和合并[1][8]

在分割阶段,算法将数组分成两个子数组,通常是平均分割。这个过程会一直进行,直到每个子数组只剩下一个元素为止[1][7]

然后,算法会递归地对这些子数组进行排序。这个过程就是所谓的“排序”步骤,它使用了同样的归并排序算法来对子数组进行排序[1][8]

最后,算法将排好序的子数组合并成一个新的有序数组。这个过程涉及到两个指针和额外的空间,它会从两个子数组中取出一个元素,比较它们的大小,然后将较小的元素放入新的数组中。这个过程会一直进行,直到两个子数组都被取完,然后将剩下的元素放入新的数组中[1][2]

这就是归并排序的基本思想和步骤。归并排序的时间复杂度为O(nlogn),空间复杂度为O(n),它是一个稳定的排序算法,也就是说相等元素的相对顺序在排序后不会改变[3][8]

image-20231010235203740


归并排序的时间复杂度

image-20231010235345035


各种排序的(最好,最坏,平均,稳定性)时间复杂度和空间复杂度

image-20231010100128067


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值