排序(3)
七. 基数排序
规则:低位优先,所有数据从低位开始,依次放入到对应的十个桶内,再依次从桶中将数据取出
时间复杂度: O(n*log(2,n))
空间复杂度: O(n)
稳定性: 稳定
static int Get_Figure(int ar[], int len)//获取最大值的位数 { int max = ar[0]; for (int i = 1; i < len; i++) { if (max < ar[i]) { max = ar[i]; } } int count = 0; while (max != 0) { count++; max /= 10; } return count; } static int Get_Num(int n, int fin) { int num = 0; while (fin != 0) { n = n / 10; fin--; } num = n % 10; return num; } static void Radix(int ar[], int len, int fin)//二维数组 { int bucket[10][20] = { 0 };//创建10个桶,每个桶有20个空间 int num[10] = { 0 };//存放每个桶中存放的数据量 for (int i = 0; i < len; i++) { int index = Get_Num(ar[i], fin); bucket[index][num[index]++] = ar[i]; } //此时数据都以fin位依据,存放在桶中. int k = 0; for (int i = 0; i < 10; i++)//从桶内依次取值,放入数组中 { for (int j = 0; j < num[i]; j++) { ar[k++] = bucket[i][j]; } } } /* static void Radix2(int ar[], int len, int fin)// 链式队列也ok { LinkQueueHead quearr[10]; for (int i = 0; i < 10; i++) { InitLinkQueue(&quearr[i]); } for (int i = 0; i < len; i++) { int index = Get_Num(ar[i], fin); Push(&quearr[index], ar[i]); } int k = 0; for (int i = 0; i < 10; i++)//从桶内依次取值,放入数组中 { while (!IsEmpty(&quearr[i])) { Pop(&quearr[i], &ar[k]); k++; } } for (int i = 0; i < 10; i++) { Destory(&quearr[i]); } } */ void RadixSort(int ar[], int len) { assert(ar != NULL && len > 1); int count = Get_Figure(ar, len); for (int i = 0; i < count; i++)//循环次数 { Radix2(ar, len, i); } }
八. 快速排序:越有序,越慢.
规则: 选择一个基准值,以基准值为界限,左边的值大于基准值,右边的值大于基准值
1.从右向左找比基准值小的数,往前放
2.从左向右找比基准值大的数,往后放
3.重复1,2,直达left == right 将基准数放到ar[left]中
4.将所有基准数归位,则排序完成
时间复杂度: O(nlog(2,n))
空间复杂度: O(1)
稳定性: 不稳定
优化:
1. 如果有效数值较少,则选择直接插入排序
2. 对基准数的选:三数取中
3. 防止完全有序,自己打乱
static int onePaition(int ar[], int left, int right)//单向逼近
{
int tmp = ar[left];
int i = left;
int j = left -1; //记录最后一个比tmp小的数的下标.
for(; i<=right; i++)
{
// 4 5 6 3 2 1 7
if(ar[i] < tmp)
{
j++;
std::swap(ar[j],ar[i]);
}
}
std::swap(ar[j],ar[left]);//将基准数归位.
return j;
}
static int Parition(int ar[], int left, int right)//将ar[left]作为基准数归位(双向逼近) { int tmp = ar[left]; while (left < right) { while (tmp < ar[right] && right > left) { right--; } if (right > left) ar[left] = ar[right]; while (tmp >= ar[left] && right > left) { left++; } if (right > left) ar[right] = ar[left]; } ar[right] = tmp; return left; } void Quick_Stack(int ar[], int left, int right) //用栈实现非递归的快排 { stack <int> st; if (left < right) { int midindex = Parition(ar, left, right); if (left < midindex - 1) { st.push(left); st.push(midindex -1); } if (midindex + 1 < right) { st.push(midindex + 1); st.push(right); } } while (!st.empty()) { int R = st.top(); st.pop(); int L = st.top(); st.pop(); int index = Parition(ar, L, R); if (L < index - 1) { st.push(L); st.push(index - 1); } if (index + 1 < R) { st.push(index + 1); st.push(R); } } } void QuickPass(int ar[], int left,int right)//递归实现 { if (left >= right) { return; } int p = Parition(ar, left, right); QuickPass(ar, left, p - 1); QuickPass(ar, p + 1, right); } void QuickSort(int ar[], int len) { assert(ar != NULL && len > 1); //QuickPass(ar,0, len - 1); Quick_Stack(ar, 0, len-1); }
总结:
//关于排序算法 //1.算法的描述 2.算法的实现 3.效率(时间复杂度,空间复杂度 以及稳定性) // 稳定性: 如果两个关键值A和A^相等,初始时A在A^前面,排序后仍然是这样,则称是稳定的 // // // 目录: 效率分析: 稳定性: // 1.冒泡排序(沉石排序) 时间复杂度 O(n^2) 空间复杂度 O(1) 稳定 // 2.直接插入排序 时间复杂度 O(n^2) 空间复杂度 O(1) 稳定 // 3.希尔排序 时间复杂度 O(n^1.3 - 1.5) 空间复杂度 O(1) 不稳定 // 4.二路归并排序 时间复杂度 O(n*log(n)) 空间复杂度 O(n) 稳定 // 5.(简单)选择排序 时间复杂度O(n^2) 空间复杂度O(1) 不稳定 // 6.堆排序 时间复杂度 O(n*log(2,n)) 空间复杂度 O(1) 不稳定 // 7.基数(桶)排序 时间复杂度O(n) 空间复杂度O(n) 稳定 // 8.快速排序 时间复杂度O(nlog(2,n)) 空间复杂度O(1) 不稳定