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

目录

1.冒泡排序

1.1.算法思想

1.2.代码

1.3.时间复杂度和稳定性

2.快速排序

2.1.算法思想

2.2.代码

2.3.时间复杂度和稳定性

3.王道课后题


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
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

25.low指向的元素为65 < 76,low++

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

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

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

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

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.王道课后题

//交换元素
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
}

时间最少——快速排序

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

//交换函数
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);
    }
}

//划分并且排序
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);
}
    

//交换数组元素
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++;
    }
}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值