01归并排序

归并排序就是先将一个数组的左侧与右侧都有序,然后用两个指针分别比较两个数组元素的大小,将比较结果复制到辅助数组中。
整体采用递归方法,确定递归基是需要排序的序列只有一个数的时候。其余情况,则需要不断向下继续递归。

void mergesort(int l,int r,int arr[])
{if(l == r)return;int m = l+(r-l)>>1;mergesort(l,m,arr);mergesort(m+1,r,arr);merge(l,m,r,arr);
}

如果l=r的时候,说明需要排序的序列只有一个数,必然是有序的,所以直接返回。
接下来看merge方法,将两个有序序列合并成为一个有序序列的过程。

void merge(int l,int m,int r,int arr[])
{int help[ARR_MAX];int i = 0;int p1 = l;int p2 = m + 1;while(p1<=m &&p2<=r){help[i++] = (arr[p1]>arr[p2]? arr[p2++]:arr[p1++]);}while(p1<=m){help[i++] = arr[p1++];}while(p2<=r){help[i++] = arr[p2++] ;}for(i = 0; i < r-l+1; i++){arr[l+i] = help[i];}
}
  1. 开辟一个辅助数组,大小与原数组相同,该数组的元素用一个指针位置i来表示。
    用p1代表左侧序列的下标位置,初始值就是左边界l,最大值是m,
    p2代表右侧序列的下标位置,初始值就是m+1,最大值是r。
  2. 若两个序列的指针都没有超过最大值
    若左侧序列的对应元素小于等于右侧序列的对应元素,就将左侧序列的对应元素复制到辅助数组中。若左侧对应数组大于右侧序列的对应元素,则将右侧序列的对应元素复制到辅助数组中。这一过程中,复制元素的序列和辅助数组,对应的指针位置都需要后移。
  3. 若有一个序列的指针越界,则需将另一个序列中剩余的元素都依次复制到辅助数组中。
  4. 最终将辅助数组中的元素,复制到原数组中。

完整测试代码

#include <iostream>
#include<time.h>
#define B_MAX 7
using namespace std;void merge(int l, int m, int r, int* b)
{int help[B_MAX];int i = 0;int p1 = l;int p2 = m + 1;while (p1 <= m && p2 <= r){help[i++] = (b[p1] > b[p2] ? b[p2++] : b[p1++]);}while (p1 <= m){help[i++] = b[p1++];}while (p2 <= r){help[i++] = b[p2++];}for (i = 0; i < r - l + 1; i++) {b[l + i] = help[i];}
}void mergesort(int l, int r, int* b)
{if (l == r)return;int m = (r + l) / 2;mergesort(l, m, b);mergesort(m + 1, r, b);merge(l, m, r, b);
}int main()
{srand((unsigned)time(NULL));int b[B_MAX];for (int i = 0; i < B_MAX; i++){b[i] = rand() % 10;cout << b[i] << ' ';}cout << endl;mergesort(0, B_MAX - 1, b);for (int i = 0; i < B_MAX; i++){cout << b[i] << ' ';}system("pause");return 0;
}

时间复杂度分析
使用master公式
T(N)=2T(N/2)+O(N)
a=2 b=2 d=1
符合log b a=d 所以归并排序的时间复杂度为O(N*logN)

02归并排序拓展

小和问题与逆序对问题

小和问题

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子 1,3,4,2,5
1左边比1小的数,没有;
3左边比3小的数,1;
4左边比4小的数,1,3;
2左边比2小的数,1;
5左边比5小的数,1,3,4,2;
所以小和是这些数累加起来和为16
分析:求小和就是遍历当前数组,选择一个数,让这个数与左边的数依次比较,若左边的数小于当前数,则将该数累加到小和结果中。换种情况来考虑问题,求小和就是看当前数的右侧有几个数比当前数大,那么就加几倍的当前数。换个角度分析之后,时间复杂度还是一样的,我们使用归并排序的思想,使得在两组序列merge的时候,计算当前的小和。因为这两个系列都是有序的,所以不需要全部遍历,只需要计算右侧序列的下标即可。

     while (p1 <= m && p2 <= r) {//都不越界的时候res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;//只有左组比右组小,才产生小和数量增加的行为,当前右组有多少个数比p1大help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];}

在排序的同时记录小和结果,当右侧序列数大于当前左侧序列数的时候,小和增加(r - p2 + 1)倍的当前左侧数。当左组与右组的数相等时,需要先向下拷贝右组的数,因为不这样,不知道右组有几个数比当前数大。
完整代码

#include<iostream>
#define ARR_Length 5
using namespace std;
int merge(int l, int m, int r, int *b)
{int help[ARR_Length];int p1 = l;int p2 = m + 1;int i = 0;int result = 0;while (p1 <= m && p2 <= r){result += b[p1] < b[p2] ? ((r - p2 + 1) * b[p1]) : 0;help[i++] = b[p1] > b[p2] ? b[p2++] : b[p1++];}while (p1 <= m){help[i++] = b[p1++];}while (p2 <= r){help[i++] = b[p2++];}for (i = 0; i < r - l + 1; i++){b[i + l] = help[i];}return result;
}int mergesort(int l, int r, int *b)
{if (l == r)return 0;int m = l + ((r - l) >> 1);return mergesort(l, m, b) //左侧排好并取小和+ mergesort(m + 1, r, b) //右侧排好并取小和+ merge(l, m, r, b);//merge时产生小和
}int main()
{int b[ARR_Length] = { 1,3,4,2,5 };int a = 0;a = mergesort(0, ARR_Length - 1, b);cout << a;return 0;
}

逆序对

在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对,请打印所有的逆序。
分析:找逆序的过程就是在归并的过程中,如果左边的数大于右边的数,那么计算左侧序列的下标,记录逆序数,然后将逆序数都打印出来
完整代码

#include<iostream>#define B_Length 5
using namespace std;
int merge(int l, int m, int r, int b[])
{int help[B_Length];int p1 = l;int p2 = m + 1;int i = 0;int result = 0;while (p1 <= m && p2 <= r){result += b[p1] > b[p2] ? (m - p1 + 1) : 0;if (b[p1] > b[p2])for (int i = p1; i <= m; i++) {cout << b[i] << b[p2] << endl;}help[i++] = b[p1] > b[p2] ? b[p2++] : b[p1++];}while (p1 <= m){help[i++] = b[p1++];}while (p2 <= r){help[i++] = b[p2++];}for (i = 0; i < r - l + 1; i++){b[i + l] = help[i];}return result;
}int mergesort(int l, int r, int b[])
{if (l == r)return 0;int m = l + ((r - l) >> 1);return mergesort(l, m, b) + mergesort(m + 1, r, b) + merge(l, m, r, b);
}int main()
{int b[B_Length] = { 1,3,4 ,2,5 };int a = 0;a = mergesort(0, B_Length - 1, b);cout << a;system("pause");return 0;
}

03堆

  1. 堆结构就是用数组实现的完全二叉树结构。
  2. 完全二叉树中如果每棵树的最大值在顶部就是大根堆
  3. 完全二叉树中如果每棵树的最小值在顶部就是小根堆
  4. 堆结构的heapinsert和heapify操作
  5. 堆结构的增大和减小
  6. 优先级队列结构就是堆结构

什么是完全二叉树?二叉树是的,若是不满也是从左到右依次变满
数组从0出发的连续一段可以对应成完全二叉树(数组元素按二叉树行依次添加)
堆结构节点与数组对应位置关系
左孩子节点为2i+1,右孩子节点为2i+2 父节点为(i-1)/2

heapInsert:新节点插入进来,并向上调整形成大根堆的过程

分析:某个数现在处在index位置,往上继续移动,将当前数与父位置的数进行比较,若当前数大于父位置的数,则两个数交换位置,index更新到刚才父节点的位置。

//某个数现在处在index位置,往上继续移动
void heapinsert(int arr[],int index)
{while(arr[index] > arr[(index-1)/2])//若当前的数大于父位置的数{swap(arr[index],arr[(index-1)/2]);index = (index-1)/2;//换完后来到父位置,继续在循环中判断 直到不比父节点大 或到达根节点}
}

使用for循环遍历数组,调用heapinsert

for(int i = 0;i < length;i++ ){heapinsert(arr,i);//用for循环传入要处理的index}

时间复杂度分析
插入一个数需要比较数的高度次,也就是O(logN),N个数需要比较log1+log2+…+log(N-1)=O(N)

heapify 假设数组中某个值变小,重新将数组调整为大根堆的过程

分析:找到这个数的左右孩子的最大值,将左右孩子的最大值与这个数进行比较,
若孩子节点大于父节点,交换位置。
停止条件:左右孩子的最大值小于等于父节点或者 没有左右节点

//某个数在index位置,能否往下移动
void heapify(int arr[],int index,int heapsize)
{int left = index * 2 + 1; //左孩子的下标while(left < heapsize){ //两个孩子中,谁的值大,把下标给largeint largest = left + 1 < heapsize && arr[left]<arr[left + 1] ? left + 1:left;//父亲和较大孩子之间,谁的值大,就把下标给largestlargest = arr[largest] > arr[index] ? largest : index;if(largest == index)//父节点就是三个节点中的最大值break;swap(arr[largest],arr[index]);index = largest;//向下移动left =  index * 2 + 1;}
}

04堆排序

  1. 先让整个数组都变成大根堆结构,建立堆的过程
    1.1 从上到下的方法,时间复杂度O(N*logN)(0-0位置是大根堆,依次插入数组元素进行heapInsert)
    1.2 从下到上的方法,时间复杂度为O(N)(先让最底层的节点heapify,再让上一层的,不断依次向上heapify)
  2. 把堆的最大值与堆末尾的值交换,然后减少堆的大小后,再去重新调整堆为大根堆,一直周而复始,时间复杂度为O(N*logN)
  3. 堆的大小减小为0的时候,排序完成。

排序代码

void heapsort(int arr[],int heapsize)
{while(heapsize > 0){heapify(arr,0,heapsize);//O(logN) 0位置数往下heapifyswap(arr[0],arr[--heapsize]);//O(1) 0位置与当前末位置交换}
}

堆排序完整代码

#include<iostream>
#include<time.h>
#define length 10
using namespace std;void swap(int& a, int& b)
{int temp = a;a = b;b = temp;
}void heapify(int arr[], int index, int heapsize)
{int left = 2 * index + 1;while (left < heapsize){int largest = left + 1 < heapsize && arr[left + 1] > arr[left] ?left + 1 : left;largest = arr[index] < arr[largest] ? largest : index;if (index == largest)break;swap(arr[index], arr[largest]);index = largest;left = 2 * index + 1;}}void heapsort(int arr[], int heapsize)
{while (heapsize > 0){heapify(arr, 0, heapsize);//O(logN) 0位置数往下heapifyswap(arr[0], arr[--heapsize]);//O(1) 0位置与当前末位置交换}
}void heapinsert(int arr[], int index)
{while (arr[index] > arr[(index - 1) / 2]){swap(arr[index], arr[(index - 1) / 2]);index = (index - 1) / 2;}
}int main()
{srand((unsigned)time(NULL));int arr[length];int heapsize = length;cout << "arr = ";for (int i = 0; i < heapsize; i++){arr[i] = rand() % 10;cout << arr[i] << " ";heapinsert(arr, i);}cout << endl << "arr1 = ";heapsort(arr, heapsize);for (int i = 0; i < length; i++){cout << arr[i] << " ";}cout << endl;//system("pause");return 0;
}

05堆排序扩展题目

已知一个几乎有序的数组,几乎有序是指如果数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
分析:将0-k位置的数置为小根堆,0位置必然是小根堆的最小值,将0位置弹出,将k+1位置的数插入,每次添加一个数就弹出一个数,没有数需要插入时,依次弹出小根堆中的数

排序java代码

public void sortedArrDistanceLessK(int[] arr, int k) {PriorityQueue<Integer> heap = new PriorityQueue<>();//默认为小根堆int index = 0;for (; index <= Math.min(arr.length, k); index++) {//把前k+1个数放到小根堆heap.add(arr[index]);}int i = 0;for (; index < arr.length; i++, index++) {//每次添加一个数,弹出一个数heap.add(arr[index]);arr[i] = heap.poll();}while (!heap.isEmpty()) {//没有数需要添加后,依次弹出小根堆中的数arr[i++] = heap.poll();}}

06荷兰国旗问题

问题一

给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)

分析:开辟一个小于等于num的区域,然后将这个区域的初始位置置于数组边界左侧,通过与数组元素的比较的过程,小于等于区域不断推着大于区域向右移动,直到将数组元素遍历完。
具体的比较规则

代码

#include<iostream>
#include<time.h>
#define arr_length 10
using namespace std;//交换函数
void swap(int &a,int &b)
{int temp = a;a = b;b = temp;
}int main()
{int arr[arr_length];int cur = 0;int num = 6;int x = -1;//生成随机长度为arr_length的数组,并输出srand((unsigned)time(NULL));cout<<"arr = ";for(int i = 0;i < arr_length;i++){arr[i] = rand()%10;cout<<arr[i]<<" ";}cout<<endl;//核心代码while(cur < arr_length){if(arr[cur] <= num){swap(arr[cur++],arr[++x]);}else{cur++;}}//输出交换后的arr1,arr2cout<<"arr1 = ";for(int i = 0;i<=x;i++){cout<<arr[i]<<" ";}cout<<endl;cout<<"arr2 = ";for(int i = x+1;i<arr_length;i++){cout<<arr[i]<<" ";}cout<<endl;system("pause");return 0;
}

问题二

给定一个数组arr,和一个数num,请将小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)

分析:再看问题二,两个问题的区别就是问题二中需要将等于num的数放在中间,那么我们可以在问题一的基础上再开辟一个大于num的区域,位于数组的右侧。

小于区域推着等于区域奔向大于区域,大于区域往左压缩待定位置
代码

#include<iostream>
#include<time.h>
#define arr_length 5
using namespace std;//交换函数
void swap(int &a,int &b)
{int temp = a;a = b;b = temp;
}int main()
{int arr[arr_length];int cur = 0;int num = 6;int x = -1;int y = arr_length;//生成随机长度为arr_length的数组,并输出srand((unsigned)time(NULL));cout<<"arr = ";for(int i = 0;i < arr_length;i++){arr[i] = rand()%10;cout<<arr[i]<<" ";}cout<<endl;//核心代码while(cur < y){if(arr[cur] < num){swap(arr[cur++],arr[++x]);}else if(arr[cur] == num){cur++;}else{swap(arr[cur],arr[--y]);}}//输出交换后的arr1,arr2,arr3cout<<"arr1 = ";for(int i = 0;i<=x;i++){cout<<arr[i]<<" ";}cout<<endl;cout<<"arr2 = ";for(int i = x+1;i<y;i++){cout<<arr[i]<<" ";}cout<<endl;cout<<"arr3 = ";for(int i = y;i<arr_length;i++){cout<<arr[i]<<" ";}cout<<endl;system("pause");return 0;
}

07不改进的快速排序

快排1.0

基于问题一,整个数组中,拿最后一个数当做num
按规则划分区域后,将大于区域的第一个数与当前数(最后一个数 )交换位置
然后让左侧和右侧重复这个操作,每次递归都会有一个数排好位置
代码

#include<iostream>
#include<time.h>
#define length 10
using namespace std;//交换函数
void swap(int &a,int &b)
{int temp = a;a = b;b = temp;
}int partition(int arr[],int l,int r)
{int num = arr[r]; //把最后一个数设为num进行比较int x = l-1;      //x为小于等于的区域,设为区域之前一个位置int cur = l;      //cur是当前遍历的指针while(cur < r+1)   //遍历所有位置{if(arr[cur]<=num){swap(arr[cur++],arr[++x]);}elsecur++;}return x-1;
}void quicksort(int arr[],int l,int r)
{if(l<r){int a = partition(arr,l,r);quicksort(arr,l,a);quicksort(arr,a+1,r);}
}int main()
{//准备随机数组int arr[length] ;srand((unsigned)time(NULL));cout<<"arr = ";for(int i = 0;i < length;i++){arr[i] = rand()%10;cout<<arr[i]<<" ";}cout<<endl;//意外情况直接返回(本题用不到)if (arr == NULL || length < 2) {return 0 ;}//核心quicksort(arr,0,length - 1);//结果输出cout<<"arr = ";for(int i = 0;i<length;i++){cout<<arr[i]<<" ";}cout<<endl;system("pause");return 0 ;
}

快排2.0

分析快排1.0的缺点:每次只能找出一个等于num的数进行排序,如果存在多个相同的num还需要继续划分,多做了很多无用功。基于问题二荷兰国旗,每次可以搞定一批等于num的位置,会使时间复杂度的常数项大大降低。
代码

#include<iostream>
#include<time.h>
#define length 20
using namespace std;void swap(int &a,int &b)
{int temp = a;a = b;b = temp;
}int* partition(int arr[],int l,int r,int a[])
{int x = l-1;int y = r+1;int cur = l;int num = arr[r];while(cur<y){if(arr[cur]<num){swap(arr[cur++],arr[++x]);}else if(arr[cur]>num){swap(arr[cur],arr[--y]);}else{cur++;}}a[0] = x;a[1] = y;return a;
}void quicksort(int arr[],int l,int r)
{int a[2] = {0};if(l<r){int *p = partition(arr,l,r,a);quicksort(arr,l,*p);quicksort(arr,*(p+1),r);}
}int main()
{//生成随机数组int arr[length];srand((unsigned)time(NULL));cout<<"arr = ";for(int i = 0;i<length;i++){arr[i] = rand()%10;cout<<arr[i]<<" ";}cout<<endl;quicksort(arr,0,length - 1);//打印结果cout<<"arr1 = ";for(int i = 0;i<length;i++){cout<<arr[i]<<" ";}cout<<endl;system("pause");return 0;
}

08 随机快速排序

分析:荷兰国旗的快排2.0版本的缺点在于使用最后一个数作为num,那么此时的复杂度便于数据状况有关,若原数组的本来就是有序的,那么此时的复杂度便很高。如果从数组元素中随机选择一个数,就可以绕开原始数据状况,时间复杂度变为长期的期望值。
选择数据组随机一个数int num = arr[l+rand()%(r-l+1)];
代码

#include<iostream>
#include<time.h>
#define length 20using namespace std;
void swap(int &a,int &b)
{int temp = a;a = b;b = temp;
}
//这是一个处理arr[l..r]的函数
//返回一个长度为2的数组
int* partition(int arr[],int l,int r,int a[])
{int x = l-1;//返回数组的左边界int y = r+1;//返回数组的右边界int cur = l;int num = arr[l+rand()%(r-l+1)];//等概率随机选一个位置,与最右侧的数交换while(cur<y){if(arr[cur]<num){swap(arr[cur++],arr[++x]);}else if(arr[cur]>num){swap(arr[cur],arr[--y]);}else{cur++;}}a[0] = x;a[1] = y;return a;
}void quicksort(int arr[],int l,int r)
{int a[2] = {0};if(l<r){int *p = partition(arr,l,r,a);quicksort(arr,l,*p);quicksort(arr,*(p+1),r);}
}int main()
{//生成随机数组int arr[length];srand((unsigned)time(NULL));cout<<"arr = ";for(int i = 0;i<length;i++){arr[i] = rand()%100;cout<<arr[i]<<" ";}cout<<endl;quicksort(arr,0,length - 1);//打印结果cout<<"arr1 = ";for(int i = 0;i<length;i++){cout<<arr[i]<<" ";}cout<<endl;system("pause");return 0;
}

随机选择一个数,与最后一个数交换,然后开始划分区域。最好情况与最坏的情况都是概率事件。每种事件都是1/n,概率与事件复杂度相乘累加求得期望得时间复杂度是O(N*logN)额外空间复杂度为O(logN)

算法学习02:认识O(logN)的排序相关推荐

  1. datatable的数据进行组内排序_排序算法学习分享(四)希尔排序

    排序,也称为排序算法,可以说是我们学习算法的过程中遇到的第一个门槛,也是实际应用中使用得较为频繁的算法,我将自己对所学的排序算法进行一个归纳总结与分享,如有错误,欢迎指正! 排序算法学习分享(一)选择 ...

  2. 算法学习笔记:简单数据结构及排序算法

    原学习视频跳转地址:https://www.bilibili.com/video/BV13g41157hK?p=2 本文为自学视频整理的简单笔记 目录 排序 冒泡排序 选择排序 插入排序 归并排序(递 ...

  3. 图解算法学习笔记(二): 选择排序

    目录 1)数组和链表: 2)选择排序算法: 3)小结 本章内容: 两种基本数据结构:数组和链表: 选择排序算法: 1)数组和链表: 数组是连续的内存单元,链表可以不连续: 链表存储单元如图所示,每一个 ...

  4. 3D激光雷达SLAM算法学习02——3D激光雷达传感器

    1.本篇思维导图 2. 3D激光雷达传感器分类 3. 机械激光雷达 直观视频感受:Velodyne 优点:360°视野,精度高,工作稳定,成像快 缺点:成本较高,不符合自动驾驶车规,生命周期短, 主要 ...

  5. 冒泡和快速排序的时间复杂度_排序算法学习分享(二)交换排序---冒泡排序与快速排序...

    排序,也称为排序算法,可以说是我们学习算法的过程中遇到的第一个门槛,也是实际应用中使用得较为频繁的算法,我将自己对所学的排序算法进行一个归纳总结与分享,如有错误,欢迎指正! 排序算法学习分享(一)选择 ...

  6. 基本算法学习(一)之希尔排序(JS)

    参考书: 严蔚敏-数据结构 希尔排序(Shell's Sort) 希尔排序又称"缩小增量排序",归属于插入排序一类,简单来说,和我们的插入排序比,它更快. 奇妙的记忆点: 内排序( ...

  7. 推荐系统遇上深度学习(二十)-贝叶斯个性化排序算法原理及实战

    排序推荐算法大体上可以分为三类,第一类排序算法类别是点对方法(Pointwise Approach),这类算法将排序问题被转化为分类.回归之类的问题,并使用现有分类.回归等方法进行实现.第二类排序算法 ...

  8. 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序

    拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...

  9. 算法学习总结(2)——温故十大经典排序算法

    一.什么是排序算法 1.1.排序定义 对一序列对象根据某个关键字进行排序. 1.2.排序术语 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面: 不稳定:如果a原本在b的前面,而a=b,排 ...

最新文章

  1. 《强化学习周刊》第4期:强化学习应用之智慧交通
  2. linux下面显示所有正在运行的线程
  3. C语言程序流程设计之跳转【程序流程设计】(14)
  4. plSQL复制数据的方法
  5. mysql 日均pv100w_日均百万PV架构第四弹(分布式监控)_MySQL
  6. 利用nvm管理Node的版本
  7. ECCV 2020 论文大盘点-3D人体姿态估计篇
  8. 网页web前端学习技巧
  9. Android操作系统手机遇冷 国外辉煌国内难现
  10. java 中button和jbutton输出的按钮不一样_Java学习教程(基础)--Java开发环境搭建
  11. 腾讯云云服务器迁移服务相关问题
  12. 中台能力是什么?PaaS是什么?微服务是什么?
  13. CodeForces 1463 C. Busy Robot 模拟
  14. Android 音视频开发之基础篇 使用 imageview绘制一张图片
  15. Qt VTK软件开发问题学习记录
  16. 用Allegro导出DXF/DWG格式文件
  17. boost circular_buffer
  18. 光学雨量计对比翻斗式雨量计的优势
  19. 什么是CUSDEC 报关单?
  20. 公共关系礼仪实务章节测试题——公共关系的类型(四)

热门文章

  1. Java项目+打包+部署
  2. python+selenium 中input标签 框无法选中和点击、输入等元素操作,如何触发该元素框数据加载
  3. 编译型语言与解释型语言的区别
  4. Tableau表格取消合并单元格
  5. 曙光I620 -G30 配置 raid 步骤
  6. 高层管理者的3个“毒瘤”,才是企业的大危机
  7. 引导滤波matlab代码实现,引导图滤波(Guided Image Filtering)原理以及OpenCV实现
  8. scipy.interpolate插值方法介绍
  9. 个人创业,是先找客户还是先做产品?
  10. 亚马逊品牌备案流程步骤—Amazon商标备案的优势