算法导论第二章复习笔记

// CLRS_CHARPTER2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
//设置数组初始值
void setArray(int *arr, int len) {
    srand(time(nullptr));
    for (int i = 0; i < len; ++i)
        arr[i] = rand() % 101;
}
//数据输出函数
void print(int *arr, int len) {
    for (int i = 0; i < len; ++i)
        cout << arr[i] << " ";
    cout << endl;
}
//希尔排序
//不稳定
//时间复杂度O (n ^ 1.3)
//
void ShellSort(int *arr, int len) {
    for (int gap = len / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < len; ++i) {
            int key = arr[i];
            int j = i - gap;
            while (j >= 0 && arr[j] > arr[i]) {
                arr[j + gap] = arr[j];
                j -= gap;
            }
            arr[j + gap] =  key;
        }
    }
}
//插入排序
//时间复杂度  O(n * n)
//空间复杂度 O(1)
//原址,稳定。
//适合小数据量的排序 (len < 30)
void InsertSort(int *arr, int len) {
    for (int i = 1; i < len; ++i) {
        int j = i - 1;
        int key = arr[i];
        while (arr[j] > key && j >= 0) {
            arr[j + 1] = arr[j];
            --j;
        }
        arr[j + 1] = key;
    }
}
//折半插入排序
//在插入排序中使用二分法查找数据插入的位置。
//时间复杂度 O(n * n)
//稳定,原址
void BinaryInsertionSort(int *arr, int len) {
    for (int i = 1; i < len; ++i) {
        int key = arr[i];
        int left = 0, right = i - 1, mid;
        //找寻插入位置,这里使用了二分查找
        while (left <= right) {
            mid = (left + right) / 2;
            if (arr[mid] <= key)
                left = mid + 1;
            else 
                right = mid - 1;
        }
        //找到插入位置后进行数组移位 
        for (int j = i; j > left; --j)
            arr[j] = arr[j - 1];
        arr[left] = key; //将数据放入合适的位置
    }
}
//归并排序
//分治法的实现,将数据分为子问题求解,最后将子问题合并
//这里的merge函数是合并函数,mergesort函数是分解函数
//时间复杂度O(n *lg n) 空间复杂度O(n)
//稳定
//最好情况最坏情况时间复杂度均为O(n * lgn)
void merge(int *arr, int p, int q, int r) {
    int n1 = q - p + 1;
    int n2 = r - q;
    //辅助数组及其初始化
    int *left = new int[n1];
    int *right = new int[n2];
    for (int i = 0; i < n1; ++i)
        left[i] = arr[p + i];
    for (int i = 0; i < n2; ++i)
        right[i] = arr[q + 1 + i];
    int k = p, i = 0, j = 0;
//这里的写法跟算法导论上稍有不同
    //也可以使用算法导论上的方法,利用INT_MAX作为截至哨兵
    while (i < n1 || j < n2) {
        if (i == n1)    //left数组完毕
            arr[k++] = right[j++];
        else if (j == n2)
            arr[k++] = left[i++];
        else {
            if (left[i] < right[j])
                arr[k++] = left[i++];
            else
                arr[k++] = right[j++];
        }
    }
    delete[] left;
    delete[] right;
}
void mergeSort(int *arr, int p, int r) {
    if (p < r) {
        int q = (p + r) / 2;
        mergeSort(arr, p, q);
        mergeSort(arr, q + 1, r);
        merge(arr, p, q, r);
    }
}
int main()
{
    srand(time(nullptr));
    int arr[20];
    const int len = 20;
    setArray(arr, len);
    cout << "排序前:\n";
    print(arr, len);
    cout << "直接插入排序:" << endl;
    InsertSort(arr, len);
    print(arr, len);
/**************************************/
    //arr重新置为随机数
    setArray(arr, len);
    cout << "排序前:" << endl;
    print(arr, len);
    BinaryInsertionSort(arr, len);
    cout << "折半插入排序后:" << endl;
    print(arr, len);
/**************************************/
    //重置arr
    setArray(arr, len);
    cout << "排序前:" << endl;
    print(arr, len);
    mergeSort(arr, 0, len - 1);
    cout << "归并排序后:" << endl;
    print(arr, len);
/***************************************/
    //重置arr
    setArray(arr, len);
    cout << "排序前:" << endl;
    print(arr, len);
    ShellSort(arr, len);
    cout << "希尔排序" << endl;
    print(arr, len);
    return 0;
}

/***************************************************
>   课后题2 - 5 逆序对问题
>   思路1:使用归并排序解,在两个子数组开始合并的时候,
如在[ [1 , 3 , 5 ] ,[2 ,4 , 6 ] ] 开始合并的时候
其中3和2组成了一个逆序对,那么3后面的每一个元素都将会跟2组成一个逆序对
由此便可算得数组中的总逆序对
>   思路2:直接使用冒泡排序
****************************************************/
#include "stdafx.h"
#include <iostream>
using namespace std;
int merge(int *arr, int p, int q, int r) {
    int n1 = q - p + 1;
    int n2 = r - q;
    int *left = new int[n1];
    int *right = new int[n2];
    for (int i = 0; i < n1; ++i)
        left[i] = arr[p + i];
    for (int i = 0; i < n2; ++i)
        right[i] = arr[q + 1 + i];
    int k = p, i = 0, j = 0;
    int res = 0;
    while (i < n1 || j < n2) {
        if (i == n1)
            arr[k++] = right[j++];
        else if (j == n2)
            arr[k++] = left[i++];
        else {
            if (left[i] <= right[j])
                arr[k++] = left[i++];
            else {
                arr[k++] = right[j++];
                res += n1 - i;
            }
        }
    }
    return res;
}
int mergesort(int *arr, int p, int r) {
    int res = 0;
    if (p < r) {
        int q = (p + r) / 2;
        res += mergesort(arr, p, q);
        res += mergesort(arr, q + 1, r);
        res += merge(arr, p, q, r);
    }
    return res;
}

/*******************************************************/
//冒泡排序法
int bubbleSort(int *arr, int len) {
    int res = 0;
    for (int i  =0;i<len;++i)
        for (int j = len -1;j>i;--j)
            if (arr[j - 1] > arr[j]) {
                ++res;
                int temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
            }
    return res;
}
int main() {
    int arr[] = { 2,3,8 ,6,1 };
    cout << mergesort(arr, 0, 4) << endl;
    int arr1[] = { 2,3,8,6,1 };
    cout << bubbleSort(arr1,  4 + 1) << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值