算法基础

来源:互联网 发布:淘宝护盾 编辑:程序博客网 时间:2024/06/08 11:14

空间复杂度

类似于时间复杂度的讨论,一个算法的空间复杂度(SpaceComplexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。渐近空间复杂度也常常简称为空间复杂度。空间复杂度(SpaceComplexity)是对一个算法在运行过程中临时占用存储空间大小的量度。一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这方面的存储空间,就必须编写出较短的算法。算法在运行过程中临时占用的存储空间随算法的不同而异,有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地\”进行的,是节省存储的算法,有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法就属于这种情况。

分析一个算法所占用的存储空间要从各方面综合考虑。如对于递归算法来说,一般都比较简短,算法本身所占用的存储空间较少,但运行时需要一个附加堆栈,从而占用较多的临时工作单元;若写成非递归算法,一般可能比较长,算法本身占用的存储空间较多,但运行时将可能需要较少的存储单元。

一个算法的空间复杂度只考虑在运行过程中为局部变量分配的存储空间的大小,它包括为参数表中形参变量分配的存储空间和为在函数体中定义的局部变量分配的存储空间两个部分。若一个算法为递归算法,其空间复杂度为递归所使用的堆栈空间的大小,它等于一次调用所分配的临时存储空间的大小乘以被调用的次数(即为递归调用的次数加1,这个1表示开始进行的一次非递归调用)。算法的空间复杂度一般也以数量级的形式给出。如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为O(log2n);当一个算法的空间复杂度与n成线性比例关系时,可表示为O(n).若形参为数组,则只需要为它分配一个存储由实参传送来的一个地址指针的空间,即一个机器字长空间;若形参为引用方式,则也只需要为其分配存储一个地址的空间,用它来存储对应实参变量的地址,以便由系统自动引用实参变量。

快排

//不稳定int adjustArray(int a[], int first, int end)//first,end均为下标{    int x = a[first];    int l = first, r = end;    while (l < r)    {        //选择第一个元素作为基准,将小于他的元素放入左边,大于等于他的元素放入右边,排序不稳定        while (l<r&&a[r]>= x)            r--;        if (l < r)        {            a[l] = a[r];            l++;//将a[l]坑填好后,不再管a[l]所以,l++        }        while (l < r&&a[l] < x)            l++;        if (l < r)        {            a[r] = a[l];            r--;//将a[r]坑填好后,不再管a[r]所以,r--        }    }    //退出时,l等于r,将x填到这个坑中.    a[l] = x;    return l;}//[first,end]void quickSort(int a[],int first, int end )//first,end均为下标{    if (first < end)    {        int i = adjustArray(a, first, end);        quickSort(a, first, i - 1);        quickSort(a, i + 1, end);    }}

归并

void mergeVector(vector<int> &a, vector<int> &tmp, int left_first, int left_last,int right_first ,int right_last){    int tmp_first = left_first;    int first = left_first;    int last = right_last;;    while (left_first <= left_last&&right_first <= right_last)    {        if (a[left_first] < a[right_first])            tmp[tmp_first++] = a[left_first++];        else            tmp[tmp_first++] = a[right_first++];    }    while (left_first <= left_last)        tmp[tmp_first++] = a[left_first++];    while (right_first <= right_last)        tmp[tmp_first++] = a[right_first++];    for (int i = first; i <=last; i++)        a[i] = tmp[i];}//[firs,last]void mergeSort(vector<int> &a, vector<int> &tmp, int first, int last){    if (first < last)    {        int center = first + (last-first) / 2;        mergeSort(a, tmp, first, center);        mergeSort(a, tmp, center + 1, last);        mergeVector(a, tmp, first, center,center+1, last);    }}

插入排序

//n^2   数组默认为非降序排列void insertSort(vector<int> &vec){    //第一层循环一次遍历向量中第2个元素至最后一个元素    for (int p = 1; p < vec.size(); p++)    {        int j;        int temp = vec[p];        //将被遍历元素与之前所有元素(这些元素已经排序!)比较,从后往前遍历,找到合适位置并插入        //如果元素比他大,则继续向前寻找比他小的元素,并将大元素向后移动        for (j = p; j >0 && temp<vec[j-1]; j--)        {            vec[j] = vec[j - 1];        }        //j为插入合适位置        vec[j] = temp;    }}

希尔排序

//插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率//但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位//希尔排序,非稳定,复杂度优于等于o(n^2),与gap选择方式有关void shellsort(vector<int>&a){    for (int gap = a.size() / 2; gap > 0; gap /= 2)    for (int i = gap; i < a.size(); i++)    {        int temp = a[i];                 //谢尔排序与插入排序的共同之处        int j = i;        for (; j >= gap&& temp< a[j - gap]; j -= gap)            a[j] = a[j - gap];        a[j] = temp;    }}

冒泡排序

void bubbleSort(int a[], int n)//n代表数组大小{    //遍历一次数组,最大的一个数沉到数组末尾,n个数需要n-1次遍历    for (int i = 1; i <=n - 1; i++)    {   //n个数据需要进行n-1次交换        for (int j = 1; j <= n - i;j++)        if (a[j-1] >a[j])            swap(a[j-1], a[j]);    }}//如果对于已经排好序的数组,使用第一种方法,复杂度为O(n^2),此法可以做到O(n)void BubbleSort2(int a[], int n){    int k = n-1;    bool flag = true;    while (flag)    {        flag = false;        for (int j = 1; j <= k; j++)        if (a[j - 1] > a[j])        {            swap(a[j - 1], a[j]);            flag = true;        }        k--;    }}

二分查找

//在[start,end]范围内寻找int binary_search(const int arr[], int start, int end, int key) {    //start和end有可能重合,重合时start所对应的值有可能就是key,所以不能含等于号,    //比如数组{1,2,3}查找1,    if (start > end)        return -1;    int mid = start + (end - start) / 2; //直接平均可能會溢位,所以用此算法    if (arr[mid] > key)        return binary_search(arr, start, mid - 1, key);    if (arr[mid] < key)        return binary_search(arr, mid + 1, end, key);    return mid; //最後檢測相等是因為多數搜尋狀況不是大於要不就小於}//法2int binary_search1(const int arr[], int start, int end, int key) {    //int mid;    while (start <= end)     {        int mid = start + (end - start) / 2; ////直接平均可能會溢位,比如end和start为MAX_INT        if (arr[mid] < key)            start = mid + 1;        else if (arr[mid] > key)            end = mid - 1;        else            return mid; //最後檢測相等是因為多數搜尋狀況不是大於要不就小於    }    return -1;}

前序遍历

struct TreeNode{    int val;    TreeNode *left;    TreeNode *right;    TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};vector<int>pre(TreeNode *root){    vector<int> result;    stack<TreeNode *> sta;    TreeNode *p = root;    if (!root) return result;    else sta.push(root);    while(!sta.empty())    {        p = sta.top();        sta.pop();        result.push_back(p->val);        if (p->right)            sta.push(p->right);        if (p->left)            sta.push(p->left);    }    return result;}

中序遍历

struct TreeNode{    int val;    TreeNode *left;    TreeNode *right;    TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};//左树节点一定比右子树节点排在前边vector<int>inorder(TreeNode *root){    vector<int> result;    stack<TreeNode *> sta;    TreeNode *p = root;    if (root = nullptr) return result;    while (p != nullptr||!sta.empty())//    {        if (p != nullptr)        {            sta.push(p);            p = p->left;        }        else        {            p = sta.top();            sta.pop();            result.push_back(p->val);            p = p->right;        }    }    return result;}

后序遍历

struct TreeNode{    int val;    TreeNode *left;    TreeNode *right;    TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};//后序遍历vector<int> postorderTraversal(TreeNode* root) {    vector<int> vec;    stack<TreeNode *> sta;    TreeNode *p=root;    if (p=nullptr) return vec;    else sta.push(p);    while (!sta.empty())     {        p = sta.top();        sta.pop();        vec.insert(vec.begin(), p->val);        if (p->left) sta.push(p->left);        if (p->right) sta.push(p->right);    }    return vec;}

层序遍历

struct TreeNode{    int val;    TreeNode *left;    TreeNode *right;    TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};//层序遍历void travel(TreeNode *p, int level, vector<vector<int>>&result){    if (!p)  return ;    while (level > result.size())       result.push_back(vector<int>());    result[level - 1].push_back(p->val);    travel(p->left, level + 1, result);    travel(p->right, level + 1, result);}vector<vector<int>>level(TreeNode *root){    vector<vector<int>>result;    travel(root, 1, result);    return result;}

链表反转

struct ListNode{    int val;    ListNode *next;    ListNode(int x) : val(x), next(nullptr) { }};//正确ListNode* reverseList(ListNode* head){    if (!head||!head->next)  return head;    ListNode *dummy = new ListNode(INT_MAX);    dummy->next = head;    ListNode *prev = head;    ListNode *cur = head->next;    while (cur)    {        prev->next = cur->next;        cur->next = dummy->next;        dummy->next = cur;        cur = prev->next;  //    }    return dummy->next;}ListNode *reverseBetween(ListNode *head, int m, int n){       ListNode beg(-1);    ListNode *prev = &beg;    prev->next = head;    for (int j = 0; j < m - 1; j++)        prev = prev->next;    ListNode *newHead = prev;    prev = prev->next;    ListNode *cur = prev->next;    for (int i = 0; i < n - m; i++)//交换的次数等于节点距离    {        prev->next = cur->next;        cur->next = newHead->next;        newHead->next = cur;        cur = prev->next;    }    return beg.next;}

排序的链表中删除重复的节点

struct ListNode{    int val;    ListNode *next;    ListNode(int x) : val(x), next(nullptr) {}};//删除排好序的链表中的重复节点ListNode *deleteDuplicates(ListNode *head){    if (!head || !head->next)        return head;    ListNode *prev = head;    ListNode *cur=head->next;    if (prev->val == cur->val)    {        while (cur&&prev->val == cur->val)            cur = cur->next;        return deleteDuplicates(cur);    }    else    {        prev->next = deleteDuplicates(prev->next);        return prev;    }}

排序的链表中删除重复节点,使每个节点只出现一次

struct ListNode{    int val;    ListNode *next;    ListNode(int x) : val(x), next(nullptr) {}};//1ListNode* deleteDuplicates(ListNode* head) {    if (!head)   return nullptr;    if (!head->next)   return head;    ListNode *dummy = new ListNode(-1);    dummy->next = head;    ListNode *prev = head;    ListNode *cur = head->next;    while (cur)    {        while (cur&&prev->val == cur->val)        {            prev->next = cur->next;//            cur = cur->next;        }        if (cur)        {            prev = cur;            cur = cur->next;        }    }    return dummy->next;}

任意进制转换

void Convert(string &pSrc, string &pDst, int src, int dst, int &len){    int i,t, number = 0;    char temp;    for (i = 0; pSrc[i] != '\0'; i++)    {        if (pSrc[i] >= '0' && pSrc[i] <= '9') // 如果是数字        {            t = pSrc[i] - '0';        }        else // 否则就是字母        {            t = pSrc[i] - 'A' + 10;        }        number = number * src + t; // 将源进制数组转换成十进制数    }    i = 0;    while (number) // 进行进制转换    {        t = number % dst;        if (t >= 0 && t <= 9) // 如果是数字        {            pDst[i++] = t + '0';        }        else // 那么就是字母        {            pDst[i++] = t - 10 + 'A';        }        number /= dst;    }    len = i;    // 将转换完成的进制数按自然顺序排放    int j, k;    for ( j = 0, k = i - 1; k >= j; j++, k--)    {        temp = pDst[j];        pDst[j] = pDst[k];        pDst[k] = temp;    }    pDst[i] = '\0';}

字符串转换成整数

int atoi(string str){    int num = str.size();    int i = 0, digital = 0;    int sign = 1;    while (str[i]==' ' && i < num) i++;//str[i]==' '不等同于!str[i]    if (str[i] == '+')        i++;    else if(str[i] == '-')    {        sign = -1; i++;    }    for (; i < num;i++)    {        if (str[i]<'0' || str[i]>'9')            break;        if (digital>INT_MAX / 10 || (digital == INT_MAX / 10 && (str[i] - '0') > INT_MAX % 10))            return sign == 1 ? INT_MAX : INT_MIN;        digital = digital * 10 + str[i] - '0';    }    return sign*digital;}

字符串拷贝函数

char * Strcpy(char * destination, const char * source){    //首先需要检查目的指针与源指针是否为空!    if (!destination)        return nullptr;    if (!source)        return destination;    char *temp = destination;    while ((*destination++ = *source++) != '\0')        ;    return temp;}

字符串连接函数

char * Strcat(char * destination, const char * source){    if (!destination)        return nullptr;    if (!source)        return destination;    char *temp = destination;    while (*destination != '\0')        destination++;    while ((*destination++ = *source++) != '\0')        ;    return temp;}

字符串比较函数

//字符串比较,逐一比较每一个字符,如果相等则继续比较下一个,知道遇到不相等字符或结尾字符,//如果遇到结尾还未比较出结果,则长字符串大int Strcmp(const char * str1, const char * str2){    assert(str1&&str2);    while (*str1 == *str2)    {        if (*str1 == '\0')            return 0;        str1++; str2++;    }    return *str1 - *str2 > 0 ? 1:-1;}
0 1