【算法导论】笔记一(插入排序、归并排序、选择排序、Peek Finding、加法器、中英文字符串搜索)

来源:互联网 发布:中南大学大数据专业 编辑:程序博客网 时间:2024/06/05 21:10

在一周学习MIT算法导论课程的时候,课上和书上都碰到了一些算法,我自己一一用C++进行了实现。本文中“中英文字符串搜索”不是算法导论的内容,是一个童鞋问我的的问题。由于MIT课程的关系,注释部分我就直接用英文啦。
由于刚开始学,代码优化做的还不到位,我会逐渐逐渐进行改善。

一、插入排序

算法最坏时间复杂度(已经尝试证明):θ(n^2)

/*    Input:A set of number    Output:A ordered number*/vector<int>& insertSort(vector<int>& v){    for (int i = 0; i < v.end() - v.begin() - 1; i++)    {        for (int j = 0; j < i + 1; j++)        {            cout << i + 1 - j << " compared with " << i - j << endl;            if (v.at(i + 1 - j) > v.at(i - j))            {                int temp = v.at(i + 1 - j);                *(v.begin() + i + 1 - j) = v.at(i - j);                *(v.begin() + i - j) = temp;            }        }    }    return v;}

二、归并排序

算法最坏时间复杂度(已经尝试证明):θ(nlg(n))
在合并的时候没有采用插入“底牌”方法,而是直接通过数组长度来进行判断了,比较蛋疼。

void printVector(const std::vector<int>& v, std::string s, bool newLine){    std::cout << s << "  ";    for (int i : v)    {        std::cout << i << " ";    }    std::cout << (newLine ? "\n" : "|");}std::vector<int> mergeVector(std::vector<int>& mergedLeft, std::vector<int>& mergedRight){    printVector(mergedLeft, "           MergedLeft:", false);    printVector(mergedRight, "          MergedRight:", true);    std::vector<int> result;    int leftIndex = 0;    int rightIndex = 0;    while (true)    {        if (leftIndex < mergedLeft.size() && rightIndex < mergedRight.size())        {            if (mergedLeft.at(leftIndex) > mergedRight.at(rightIndex))            {                result.insert(result.end(), mergedLeft.at(leftIndex));                leftIndex += 1;            }            else            {                result.insert(result.end(), mergedRight.at(rightIndex));                rightIndex += 1;            }        }        else        {            break;        }    }    //insert the rest    for (int i = leftIndex; i < mergedLeft.size(); i++)    {        result.insert(result.end(), mergedLeft.at(i));    }    for (int i = rightIndex; i < mergedRight.size(); i++)    {        result.insert(result.end(), mergedRight.at(i));    }    printVector(result,"merged Vector:",true);    return result;}std::vector<int> merge_sort(std::vector<int>& v){    int middle = v.size() / 2;    //divide    if (v.size() != 1)    {        std::vector<int> leftHalf;        std::vector<int> rightHalf;        leftHalf.insert(leftHalf.begin(), v.begin(), v.begin() + middle);        rightHalf.insert(rightHalf.begin(), v.begin() + middle, v.end());        std::vector<int> mergedLeft = merge_sort(leftHalf);        std::vector<int> mergedRight = merge_sort(rightHalf);        return mergeVector(mergedLeft, mergedRight);    }    return v;}

三、选择排序

算法最坏时间复杂度(已经尝试证明):θ(n^2)

#define MAX_INT (pow(2,(sizeof(int)*8)-1)-1)    void selection_sort(int* intArray, int n)    {        for (int i = 0; i < n - 1; i++)        {            counter++;            int min = MAX_INT;            int minIndex = 0;            for (int j = i + 1; j < n; j++)            {                couter1++;                cout << "i=" << i << " j=" << j << endl;                //find the min value                if (intArray[j] < min)                {                    min = intArray[j];                    minIndex = j;                }                if (j == n - 1)                {                    int temp = intArray[i];                    intArray[i] = min;                    intArray[minIndex] = temp;                }            }        }    }

四、Peek Finding

分别实现了1D数组(使用分治法),2D数组(使用分治法、贪心法分别实现)
贪心法中加了点花头:没有按照正常顺序去找,而是把数组按照逆时针顺序输出。实现的不是很好,四个边缘点上的处理有点小复杂。网上查了查最好的办法是用递归,这样逻辑更加清晰点。
然后就是为了复习C,木有用vector和allocator,尝试用malloc和指针去指派动态数组。呵呵,复杂度增加不少。C++还是多用vector。

#include <iostream>#include <initializer_list>struct point{    int row;    int column;    int value;};/* * peekFinding using divide and conquer algorism introduced * in the lecture */point peekFinding1D(std::initializer_list<int> src){    int begin = 0;    int end = src.end() - src.begin() - 1;    while (true)    {        int middle = (end + begin) / 2;        std::cout << "middle:" << *(src.begin() + middle) << std::endl;        if (*(src.begin() + middle) <= *(src.begin() + middle + 1))        {            //throw away the left side,there might be a peek on the right            //side            begin = middle + 1;            middle = (end + begin) / 2;        }        else if (*(src.begin() + middle) <= *(src.begin() + middle - 1))        {            //throw away the right side,there might be a peek on the left            //side            end = middle + 1;            middle = (end + begin) / 2;        }        else        {            return point{0,middle,*(src.begin() + middle)};        }    }}point maximumOfRow(int* row, int length){    int max = -999;    int position;    for (int i = 0; i < length; i++)    {        if (*(row + i) > max)        {            max = *(row + i);            position = i;        }    }    return point{0,position,max};}/** peekFinding using divide and conquer algorism introduced* in the lecture*/point peekFinding2D(int** srcArray, int rows, int columns){    int y = 0;    int height = rows - 1;    while (true)    {        int middleRow = y + (height) / 2;        //Find the maximum number and it position        point p = maximumOfRow(*(srcArray + middleRow), columns);        int column = p.column;        if (middleRow != rows - 1 && middleRow != 0)        {            if (*(*(srcArray + middleRow) + column) <= *(*(srcArray + middleRow - 1) + column))            {                y = middleRow - 1;                height /= 2;                //leave the right half            }            else if (*(*(srcArray + middleRow) + column) <= *(*(srcArray + middleRow + 1) + column))            {                y = middleRow + 1;                height /= 2;                //delete the right half            }            else            {                //founded                return point{middleRow,column,*(*(srcArray + middleRow) + column)};            }        }        else        {            point p = maximumOfRow(*(srcArray + middleRow), columns);            return point{middleRow,p.column,p.value};        }    }}/** peekFinding using greedy method*/point peekFinding2DGreedy(int** srcArray, int rows, int columns){    //-1=left 1=right 0=don't move on x axis    int directionX = 0;    //-1=up 1=down 0=don't move on y axis    int directionY = 0;    int currentRow = 0;    int currentColumn = 0;    int boundX = 0;//record which circle it had entered    int boundXLimit;    if (columns % 2 == 0)    {        boundXLimit = columns / 2 - 1;    }    else    {        boundXLimit = (columns + 1) / 2 - 1;    }    int boundY = 0;    int boundYLimit = 0;    if (rows % 2 == 0)    {        boundYLimit = rows / 2 - 1;    }    else    {        boundYLimit = (rows + 1) / 2 - 1;    }    bool justStart = true;    for (int i = 0; i < rows * columns; i++)    {        currentRow += directionY;        currentColumn += directionX;        if (currentRow == boundX && currentColumn == boundX)        {            //top-left-corner            directionX = 0;            directionY = 1;            if (!justStart)            {                if (boundX < boundXLimit)                {                    boundX += 1;                }                if (boundY < boundYLimit)                {                    boundY += 1;                }                currentColumn += 1;                currentRow += 1;                justStart = true;            }        }        else if (currentRow == boundX && currentColumn == columns - 1 - boundX)        {            //top-right-corner            directionX = -1;            directionY = 0;            justStart = false;        }        else if (currentRow == rows - 1 - boundX & currentColumn == boundX)        {            //bottom-left-corner            directionX = 1;            directionY = 0;        }        else if (currentRow == rows - 1 - boundX && currentColumn == columns - 1 - boundX)        {            //bottom-right-corner            directionX = 0;            directionY = -1;        }        /*         * check if it is the peek        */        if ((currentColumn == 0 || (*(*(srcArray + currentRow) + currentColumn) >= *(*(srcArray + currentRow) + currentColumn - 1)))            && (currentColumn == rows - 1 || (*(*(srcArray + currentRow) + currentColumn) >= *(*(srcArray + currentRow) + currentColumn + 1)))            && (currentRow == rows - 1 || (*(*(srcArray + currentRow) + currentColumn) >= *(*(srcArray + currentRow + 1) + currentColumn)))            && (currentRow == 0 || (*(*(srcArray + currentRow) + currentColumn) >= *(*(srcArray + currentRow - 1) + currentColumn))))        {            return point{currentRow,currentColumn, *(*(srcArray + currentRow) + currentColumn)};        }    }}void main(){    auto result = peekFinding1D({1, 9, 7, 4, 5});    std::cout << "1DDivideAndCounquer result[" << result.column << "]=" << result.value;    std::cin.get();    int cache[5][4] =    {{1 ,14 ,13 ,12},        {2 ,15 ,20 ,11},        {3, 16, 19, 10},        {4, 17, 18, 9},        {5, 6, 7, 8}};    int** srcArray = (int**)calloc(sizeof(int**), 5);    for (int row = 0; row < 5; row++)    {        *(srcArray + row) = (int*)calloc(sizeof(int*), 4);        for (int column = 0; column < 4; column++)        {            *(*(srcArray + row) + column) = cache[row][column];        }    };    auto result2D = peekFinding2D(srcArray, 5, 4);    std::cout << "2DDevideAndCounquer result[" << result2D.row << "][" << result2D.column << "]=" << result2D.value;    std::cin.get();    auto result2DGreedy = peekFinding2DGreedy(srcArray, 5, 4);    std::cout << "2DGreedy result[" << result2DGreedy.row << "][" << result2DGreedy.column << "]=" << result2DGreedy.value;    std::cin.get();    for (int row = 0; row < 5; row++)    {        free(*(srcArray + row));    };    free(srcArray);}

五、加法器

switch语句的使用让代码复杂了一些,比较愚笨。看了答案,用的是一种比较巧妙的方法算出了进位的数字(carry)和留下的数(current)

/** Input:Tow binary arrays* Output:A decimal number=(bin1+bin2)*/std::vector<int> manuallySumTwoBinaryNumber(std::vector<int> binArray1, std::vector<int> binArray2){    int bA1 = binArray1.end() - binArray1.begin();    int bA2 = binArray2.end() - binArray2.begin();    const int max = bA1 < bA2 ? bA2 : bA1;    std::allocator<int> allocator;    int carry = 0;    std::vector<int> binArr1(max - bA1, 0);    std::vector<int> binArr2(max - bA2, 0);    std::vector<int> result(max + 1);    for (int i:binArray1)    {        binArr1.push_back(i);    }    for (int i : binArray2)    {        binArr2.push_back(i);    }    int i = 0;    for (i = max - 1; i >= 0; i--)    {        int sum = binArr1[i] + binArr2[i] + carry;        int current = 0;        switch (sum)        {        case 0:            carry = 0;            current = 0;            break;        case 1:            carry = 0;            current = 1;            break;        case 2:            carry = 1;            current = 0;            break;        case 3:            carry = 1;            current = 1;            break;        }        result[result.size() - 1 - i] = current;    }    result[result.size() - 1] = carry;    return result;}

六、中英文混合子字符串查找

手工实现了从一个字符串里面查找一个中英文混合的子字符串。没有用到相关的标准库函数。
基本思路是:先找第一个字符,如果第一个字符匹配则匹配第二个字符,第二个匹配则匹配第三个字符……

#include <stdio.h>#include <stdlib.h>int strLen(char* begin){    int len = 0;    while (true)    {        if (*(begin + len) != '\0')        {            ++len;        }        else        {            return len;        }    }}void seperateChiAndEng(char* begin, char* end){    char* cur = begin;    while (cur != end)    {        if (*cur >= 0)        {            //english            printf("%c\n", *(cur++));        }        else        {            char cWord[3];            cWord[0] = *(cur++);            cWord[1] = *(cur++);            cWord[2] = '\0';            //chinese            printf("%s\n", cWord);        }    }}bool isChi(char* str){    if (*str > 0)    {        return false;    }    else    {        return true;    }}int findStr(char* src, char* str, int strLen){    int position = -1;    char* pointer = src;    char* firstWord;    int firstWordLen = 0;    int counter = 0;    if (isChi(pointer))    {        firstWordLen = 2;        char cache[2];        firstWord = cache;        firstWord[0] = *str;        firstWord[1] = *(str + 1);    }    else    {        firstWordLen = 1;        char cache[1];        firstWord = cache;        firstWord[0] = *str;    }    while (*pointer != '\0')    {        for (int i = 0; i < firstWordLen; i++)        {            if (*(pointer + i) == *(firstWord + i))            {                ++counter;            }        }        if (firstWordLen == counter)        {            int matched = true;            //founded the first word,check the rest of the word            position = pointer - src;            for (int j = 0; j < strLen; j++)            {                if (*(pointer + j) != *(str + j))                {                    matched = false;                    break;                }            }            if (!matched)            {                position = -1;            }            else            {                break;            }        }        else        {            ++pointer;            counter = 0;            //didn't found the first word        }    }    return position;}void main(){    printf("请输入源string(最长不超过255字节)\n");    char src[255];    scanf_s("%s", src, 255);    printf("请输入要查找的string(最长不超过255字节):\n");    char target[255];    scanf_s("%s", target, 255);    int position = findStr(src, target, strLen(target));    printf("您要查找的字符串在第%d个字节位置\n", position);    system("pause");}
1 0
原创粉丝点击