408数据结构学习笔记——冒泡排序、快速排序

简介: 408数据结构学习笔记——冒泡排序、快速排序

1.冒泡排序

1.1.算法思想

从后往前两两比较相邻元素的值,若为逆序,则交换,直到序列比较完

1.由于总是将相邻两个元素中较小的放在最前面

2.因此进行一趟冒泡以后,最左边的元素一定是最小的

3.采取递归的思想,第一轮对0-7的元素冒泡,结束后0处是最小元素

4.第二轮对1-7的元素冒泡,本轮结束后1是剩下元素中最小的

5.第三轮对2-7冒泡,这样2处的是整个列表第三小的元素

6.如此递归下去,直到对长度为1的子序列递归,这时触发递归终止条件,排序结束

(或若某次排序过程中没有发生交换,则说明数组中的元素已经整体有序,排序结束)

1.2.代码

//交换
void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}
//冒泡排序
void BubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        //标记此轮循环中是否进行了交换
        bool flag = false;
        //每次从数组中最后一个元素向前遍历,直到第i个元素
        for (int j = n - 1; j >= i; j--) {
            //将相邻两个逆序元素交换为正序,并更改flag
            if (arr[j - 1] > arr[j]) {
                swap(arr[j - 1], arr[j]);
                flag = true;
            }
        }//for
        //此次循环元素都是正序,则结束函数
        if (!flag) return;
    }//for
}

d120fba187e64e299cb77ddb844451b8.png

1.3.时间复杂度和稳定性

1.空间复杂度:O(1)

2.时间复杂度:

①最好情况:有序,比较次数n - 1,交换次数0,因此,O(n)

②最坏情况:逆序,比较次数 = 交换次数 = (n-1) + (n - 2) + ...  + 1 ,O(n^2)

3.稳定性:只有当前元素的前一个元素更大的时候才交换,相等不交换,因此,该算法稳定

if (arr[j - 1] > arr[j]) swap(arr[j - 1], arr[j]);

4.适用:链表和顺序表

2.快速排序

2.1.算法思想

1.取当前表中的第一个元素(也可以是任取)为基准元素,找到它在表中的位置,即左边元素都小于它,右边元素都大于等于它,这样基准元素就确定了它在数组中的最终位置

2.以它为分割,依次到它的左表和右表进行1操作

3.重复12,直到每个表都只有一个元素为止,则整个表都有序

2.2.代码

low指针的左边都小于基准元素,high指针的右边都大于等于基准元素

1.选取49为基准元素→low当前元素为空→high指向元素49 ≥ 基准元素49,不需要移动,high--

5f7c289dd8df45dbaf1c14c228054da5.png

2.high当前指向元素27 < 49→27交换到low指针指向的位置,high空

97d33212f9d947b1a0fa02db3c3cffdf.png

3.low当前指向元素27 < 49→low++

2ddf3064b8d64ad5afbc0f15b6783ffa.png

4.low当前指向元素38 < 49→low++

1a156060319240ed87d2551f2b5aa4f3.png

5.low当前指向元素65 > 49→65交换到high指针指向的位置,low空

3b1e6cc3072540c08478d0ecb02b4dc4.png

6.high指向的元素65 > 49→high--

b2df73a3647c462f9d26f75c1ff6a23f.png

7.high指向元素13 < 49→13交换到low指针指向的位置,high空

fdd28aabb85a41f7a68df12fe2b47a50.png

8.low指向元素13 < 49→low++d1a3ea189bcc4ced81099aed19677dce.png

9.low指向元素97 > 49→97交换到high指针指向的位置,low空

5c32e4a96f5d4d319978535b383bc3a5.png

10.high指向元素97 > 49→high--

330cae34506643538d280930e9ae3d2c.png

11.high指向元素76 > 49→high--

bb35948529fa4c41a3d5e0c15269ae1f.png

12.high和low指向同一元素,49插入此元素


cd2e73d6c78b407484c3b692db049252.png

13.对左子表划分,取27为基准元素12c2eeffdbfe41c4ba346253217be323.png

14.high指向元素13 > 27→13交换到low指针指向的位置,high空

47ec8f2b842347fba424f927c9f1ee19.png

15.low指向元素为13 < 27→low++f5224e00ce2946f8aa0b84b6f4eb6bda.png

16.low指向元素为38 > 27→27交换到high指针指向的位置,low空

7576cbafc9be44bc92f7dc0ff8867f9a.png

17.high指向元素为38 > 27→high--

cba1d432b1b845069e0c1dd0bae6b4b1.png


18.high和low指向同一元素,27插入此元素


b0b2acb3f1ac423d9e73a8c4a7453dcf.png

19.27的左右子表都为1,则不需要继续排序;对49的右子表排序,取76为基准元素

20. high指向的元素为49 < 76→49交换到low指针指向的位置,high空

8b6981c14c1f48b3890964487cdffe19.png

21.low指向的元素为49 < 76→low++a8dc65e702324fdfa81d0a77218d86bf.png

22.low指向的元素为97 > 76,97交换到high指针指向的位置,low空

f6fcf45547fb42cb942a1152f785a2d7.png

23.high指向的元素为97 > 76,high--

78dc41edc3134f4f9e977e35b840646f.png

24.high指向的元素为65 < 76,65交换到low指针指向的位置,high空

5c587883508945e4ae74f5caff925df0.png25.low指向的元素为65 < 76,low++7791cdce35fa4885bc671c2a709c4ed4.png

26.low,high指向同一元素,将76插入此元素


4b339c01f3eb40409364a349e84e5ae7.png

27.76的左子表长度为2,去左子表继续排序,取49为基准元素

d165634bc8f74980ab2255ba4ce77e11.png

28.high指向元素65 > 49,high--


cda9db4f35b34c7fb322af8c814e918d.png29.high,low指向同一元素,将49插入此元素

33480e34a5f94ff3aca386d68b4028ec.png

int Partition(int arr[], int low, int high){
    //选取第一个元素作为基准元素
    int pivot = A[low];
    //循环直到low = high
    while (low < high){
        //当前元素比基准元素小时,将此元素移动到low指向的位置
        while (low < high && arr[high] >= pivot) high--;
        arr[low] = arr[high];
        //当前元素比基准元素大时,将此元素移动到high指向的位置
        while (low < high && arr[low] < pivot) low++;
        arr[high] = arr[low];
    }
    arr[low] = pivot;
    return low;
}
//快速排序
void QuickSort(int arr[], int low, int high){
    if (low < high){
        //划分左右子表
        int pivotPos = Partition(arr, low, high);
        //左子表排序
        QuickSort(arr, low, pivotPos - 1);
        //右子表排序
        QuickSort(arr, pivoPos + 1, high);
    }
}

2.3.时间复杂度和稳定性

1.时间复杂度:O(n)* 递归深度(与二叉树树形类似)

①最好时间复杂度 O(nlogn)

②快时间复杂度 O(n^2)本来就有序,每次的划分很不均,递归深度小

2.空间复杂度:O(递归层数)

①已经有序:O(n^2)

②二分:O(logn)

3.稳定性:不稳定

4.适用:顺序表

3.王道课后题

0a3bf2c1da2748f7996ad9674aa4b041.png

//交换元素
void swap(int &i, int &j) {
    int temp = i;
    i = j;
    j = temp;
}
//冒泡排序
void BubbleSort(int arr[], int n) {
    int i = 1, head = 0, tail = n - 1;
    for (i = 1; i <= n; i++) {
        //奇数次排序
        if (i % 2) {
            for (int j = head; j < tail; j++) {
                if (arr[j] > arr[j + 1]) swap(arr[j], arr[j + 1]);
            }
            head++;
        }
        //偶数次排序
        else {
            for (int j = tail; j > head; j--) {
                if (arr[j] < arr[j - 1]) swap(arr[j], arr[j - 1]);
            }
            tail--;
        }
    }//for
}

2c096e19c0614763b13b3395c6f80f61.png

时间最少——快速排序

void QuickSort(int arr[], int low, int high){
    //pivot保存low的当前元素
    int temp = arr[low];
    while (low < high) {
        //high的当前元素不是偶数,则移动到low
        while (low < high && (arr[high] % 2)) high--;
        arr[low] = arr[high];
        //low的当前元素不是偶数,则移动到high
        while (low < high && !(arr[low] % 2)) low++;
        arr[high] = arr[low];
    }
    //将temp赋值给low
    arr[low] = temp;
}

86c74c34b16745d291e19ed9d217a6a7.png

//交换函数
void swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}
//划分和排序
void Partition(int arr[], int low, int high){
    int pivot = random() % (high - low + 1);
    swap(arr[low], arr[pivot]);
    pivot = arr[low];
    while (low < high){
        while (low < high && arr[high] >= arr[pivot]) high--;
        arr[low] = arr[high];
        while (low < high && arr[low] <= arr[pivot]) low++;
        arr[high] = arr[low];
    }
    arr[low] = pivot;
    return low;
}
//函数入口
void QuickSort (int arr[], int low, int high) {
    if (low < high){
        int qivot = Partition(arr, low, high);
        QuickSort(arr, low, qivot - 1);
        QuickSort(arr, qivot + 1, high);
    }
}

3ccad71ba2bd4860b5a30aee7d1c00da.png

//划分并且排序
int Partition(int arr[], int low, int high) {
    int pivot = arr[low];
    while (low < high) {
        while (low < high && arr[high] >= pivot) high--;
        arr[low] = arr[high];
        while(low < high&& arr[low] <= pivot) low++;
        arr[high] = arr[low];
    }
    arr[low] = pivot;
    return low;
}
//快速函数入口
int QuickSort_SearchK(int arr[], int low, int high, int k) {
    if (low < high) {
        int pivot = Partition(arr, low, high);
        //返回的数组下标为k,即为第k小元素
        if (pivot == k) return arr[pivot];
        //返回数组下标大于k,去左子表
        else if (pivot > k) return QuickSort_SearchK(arr, low, pivot - 1, k);
        //返回数组下标小于k,去右子表
        else if (pivot < k) return QuickSort_SearchK(arr, pivot + 1, high, k);
    }
    //返回-1表示没找到
    return -1;
}
int QuickSort_SearchK(int arr[], int low, int high, int k){
    int low_temp = low, high_temp = high, pivot = arr[low];
    //快速排序算法实现
    while (low < high) {
        while (low < high && arr[high] >= pivot) high--;
        arr[low] = arr[high];
        while (low < high && arr[low] <= pivot) low++;
        arr[high] = arr[low];
    }
    arr[low] = pivot;
    //判断是否当前元素在数组中的位置是否与k相等
    //相等则是第k小元素
    if (low == k) return arr[low];
    //小于则去右子表查找
    else if (low < k) return QuickSort_SearchK(arr, low_temp, low - 1, k);
    //大于则去左子表查找
    else if (low > k) return QuickSort_SearchK(arr, low + 1, high_temp, k);
}

e97deda38f8c4f00854033cd61a60177.png

//交换数组元素
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}
//0指代红,1指代白,2指蓝
void ColourSort(int arr[], int n) {
    int i = 0, h = 0, t = n - 1;
    //循环直到 i >= 尾指针t
    while (i < t) {
        //当前元素为0,与头指针交换
        if (arr[i] == 0) {
            swap(arr[i], arr[h]);
            h++;
        }
        //当前指针为2,与尾指针交换
        else if (arr[i] == 2) {
            swap(arr[i], arr[t]);
            t--;
        }
        //当前为白,往前移动一个元素
        else i++;
    }
}

55e757fb9c1449e184ac2c06f45648d8.png

1.使用快速排序排序数组A,快速排序特性:每轮确定一个元素在数组中的按顺序排列的大小位置

若n为奇数:n1 = n2 - 1,且A1的元素为A的数组下标0 - n1元素;n2为剩下元素

若n为偶数:n1 = n2,且A1的元素为A的数组下标0 - n1元素;n2为剩下元素

2.

//划分并排序
int QuickSort_Divide (int arr[], int n) {
    int low = 0, high = n - 1;
    //标记是否找到第n / 2小的元素
    bool flag = false;
    int high_temp = high, low_temp = low;
    int pivot = arr[low];
    while (!flag) {
        int pivot = arr[low];
        while (low < high) {
            while (low < high && arr[high] >= pivot) high--;
            arr[low] = arr[high];
            while (low < high && arr[low] <= pivot) low++;
            arr[high] = arr[low];
        }
        arr[low] = pivot;
        if (low == n / 2) flag = true;
        //当前元素并非n/2,更小则去右子表,更大则去左子表
        //更新low,high,low_temp,high_temp
        else if (low < n / 2) {
            high = high_temp;
            low_temp = low + 1;
            low = low_temp;
        }
        else if (low > n / 2) {
            low = low_temp;
            high_temp = low - 1;
            high = high_temp;
        }
    }//while
    int s1 = 0, s2 = 0;
    for (int i = 0; i < n / 2; i++) s1 += arr[i];
    for (int i = n / 2; i < n; i++) s2 += arr[i];
    return s2 - s1;
}






相关文章
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
24 1
|
2月前
|
算法 搜索推荐
数据结构与算法学习十一:冒泡排序、选择排序、插入排序
本文介绍了冒泡排序、选择排序和插入排序三种基础排序算法的原理、实现代码和测试结果。
21 0
数据结构与算法学习十一:冒泡排序、选择排序、插入排序
|
2月前
【初阶数据结构】打破递归束缚:掌握非递归版快速排序与归并排序
【初阶数据结构】打破递归束缚:掌握非递归版快速排序与归并排序
|
2月前
|
算法
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
|
3月前
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
|
4月前
|
存储 算法 搜索推荐
【初阶数据结构篇】冒泡排序和快速排序(中篇)
与直接插入排序法相比,比较次数一致,但冒泡排序的交换需要执行三次,而直接插入排序因为使用了tmp临时变量存储要插入的数据,只用执行一次,所以直接插入排序法效率明显更高。
35 1
|
5月前
|
搜索推荐
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
|
6月前
|
机器学习/深度学习 算法 搜索推荐
数据结构算法--2 冒泡排序,选择排序,插入排序
**基础排序算法包括冒泡排序、选择排序和插入排序。冒泡排序通过相邻元素比较交换,逐步将最大值“冒”到末尾,平均时间复杂度为O(n^2)。选择排序每次找到剩余部分的最小值与未排序部分的第一个元素交换,同样具有O(n^2)的时间复杂度。插入排序则类似玩牌,将新元素插入到已排序部分的正确位置,也是O(n^2)复杂度。这些算法适用于小规模或部分有序的数据。**
|
6月前
|
算法 搜索推荐
数据结构与算法-冒泡排序
数据结构与算法-冒泡排序
28 2
|
6月前
|
算法
数据结构与算法-快速排序
数据结构与算法-快速排序
26 1