赞
踩
void Merge(int* arr, int len, int gap) { //1.先申请辅助空间 int* brr = (int*)malloc(len * sizeof(int));//额外辅助空间brr int low1 = 0; int high1 = low1 + gap - 1; int low2 = high1 + 1; int high2 = low2 + gap - 1 < len ? low2 + gap - 1 : len - 1; //难点1 int k = 0; //k代表辅助空间brr的下标 while (low2 < len)//判断左右手都抓到子序列 判断规则:右手如果抓到,则左手也肯定抓到了 //难点2 { while (low1 <= high1 && low2 <= high2)//左手还有数据,并且右手还有数据(左手不空且右手不空) { //此时判断low1和low2指向的值,谁大谁小 if (arr[low1] <= arr[low2])//low1指向的值 小于等于 low2指向的值 { brr[k++] = arr[low1++]; /*low1++; k++;*/ } else//low1指向的值 大于 low2指向的值 { brr[k++] = arr[low2++]; } } //此时,while循环退出,代表着左手和右手抓的子序列肯定有一个空了 // 此时需要,将另一个不空的子序列的剩余值,依次挪动到辅助空间brr内 (难点3) while (low1 <= high1) //左手子序列还有值 { brr[k++] = arr[low1++]; } while (low2 <= high2) //右手子序列还有值 { brr[k++] = arr[low2++]; } //将四个指针,向右平移, 处理接下来的两个子序列 (难点4) low1 = high2 + 1; high1 = low1 + gap - 1; low2 = low2 = high1 + 1; high2 = low2 + gap - 1 < len ? low2 + gap - 1 : len - 1; } //当最大的while判断为假("while(low2 < len)//判断左右手都抓到子序列") //(难点5)代表出现了这种情况: 1.两个手都没抓到 // 2.左手抓到了,右手没抓到 // 第三种可能性:左手没抓到,右手抓到了(这种情况不存在) //上面两种情况:如果出现第一种(左右手都没抓到,刚好结束,什么都不用管) // 但是,一旦出现第二种情况(左手抓到了,右手没住到),这种情况下我们需要处理左手抓到的数据 while (low1 < len) //处理第二种情况下,左手中剩余的数据 { brr[k++] = arr[low1++]; } //此时,所有的数据都在辅助空间brr中,最后将brr中的数据全部挪动到arr中 for (int i = 0; i < len; i++) { arr[i] = brr[i]; } free(brr); } //归并排序(Merge,非递归写法): 时间复杂度O(nlogn) 空间复杂度O(n) 稳定性:稳定 void Merge_Sort(int* arr, int len) { for (int i = 1; i < len; i *= 2) //logn { Merge(arr, len, i); //单独merge函数时间复杂度O(n) 空间复杂度O(n) } }
// 合并过程 void merge__(vector<int> &arr, int l, int mid, int r) { // 在这个地方创建额外空间,是一种不好的做法,更好的做法,等下讲 vector<int> tmp(r - l + 1); int i = l, j = mid + 1, k = 0; while (i <= mid && j <= r) { if (arr[i] >= arr[j]) { tmp[k++] = arr[j++]; } else { tmp[k++] = arr[i++]; } } while (i <= mid) { tmp[k++] = arr[i++]; } while (j <= r) { tmp[k++] = arr[j++]; } for (k = 0, i = l; i <= r; ++i, ++k) { arr[i] = tmp[k]; } } // 递归划分过程 void merge_sort__(vector<int> &arr, int l, int r) { // 只有一个数字,则停止划分 if (l >= r) { return; } int mid = l + ((r - l) >> 1); merge_sort__(arr, l, mid); merge_sort__(arr, mid + 1, r); // 合并两个有序区间 merge__(arr, l, mid, r); } // 要排序的数组 arr void merge_sort(vector<int>& arr) { merge_sort__(arr, 0, arr.size() - 1); }
//获取数组arr中最大值的位数 int Get_Max_count(int *arr, int len) { int max = arr[0]; for(int i=1; i<len; i++) { if(arr[i] > max) { max = arr[i]; } } int count = 0; while(max != 0) { count++; max /= 10;//max = max /10; } return count; } //获取值n,对应的fin位 是多少 //例如 123,0 -> 3 //例如 12345,3 -> 2 //例如 221,5 -> 0 000221,5 -> 0 int Get_Num_Finger(int n, int fin) //%10 取最低位 /10扔掉最低位 { for(int i=0; i<fin; i++) { n = n/10; } return n%10; } //将单独的一次桶排序看做一个模块 时间复杂度O(n) 空间复杂度O(n) // fin 代表按第几位进行一次单独的桶排序 // fin=0 代表按个位 fin=3 代表按千位 void Radix(int *arr, int len, int fin) { //1.先申请十个桶(队列),按照0~9标号 std::queue<int> bucket[10];//10个桶就申请好了 //2.将所有的数据放进去(将所有的数据按顺序,根据其对应的位,放到对应的桶内) for(int i=0; i<len; i++) { int index = Get_Num_Finger(arr[i], fin);//首先获取这个数arr[i]的fin位 对应 几号桶 bucket[index].push(arr[i]);//将arr[i]放到对应的桶内 } int k = 0; //k代表重新放到arr中的下标 //3.将所有的数据取出来(按照0号桶~9号桶的顺序,依次将桶内值全部取完(队列)) for(int i=0; i<=9; i++)//i代表桶号 { while(!bucket[i].empty())//保证将i号桶内值全部取出 { arr[k++] = bucket[i].front();//取出来的值,按照顺序重新放到arr中即可 bucket[i].pop(); //int tmp = bucket[i].front();//取出来的值,按照顺序重新放到arr中即可 //bucket[i].pop(); //arr[k++] = tmp; } } } //基数排序(桶排序): 假设最大值位数是d,则时间复杂度是O(d*n) 空间复杂度O(n) 稳定性:稳定 void Radix_Sort(int *arr, int len) { //单独的桶排序调用次数,由所有数据中的最大值的位数决定 int fin = Get_Max_count(arr, len);//假设最大值是12345 fin则等于5 for(int i=0; i<fin; i++) //0(个位) 1(十位) 2(百位) 3(千位) 4(万位) { Radix(arr, len, i); } }
假设最大值位数是d
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。