一.简单选择排序和堆排序
选择排序:每次从待排序队列中找到最小值,和待排序队列的第一位交换即可
选择排序具体实现代码:
//时间复杂度O(n^2) 空间复杂度O(1) 不稳定的
void SelectSort(int arr[], int len)
{
//assert int minindex;
//存放最小值的下标
for(int i=0; i<len-1; i++)
{
minindex = i;
//循环开始前先认为待排序队列的第一个值是最小值
for(int j = i+1; j<len; j++)
{
if(arr[minindex] > arr[j])
{
minindex = j;
}
}
if(minindex != i)
//这个if判断可以省略,不影响
{
int tmp = arr[minindex];
arr[minindex] = arr[i];
arr[i] = tmp;
}
}
}
二.堆排序:
堆分为两种:大顶堆和小顶堆 两个统称为堆
大顶堆:一个二叉树,父节点的值大于子节点的值
小顶堆:一个二叉树,父节点的值小于子节点的值
什么是树形结构:
二叉树,树根,深度,叶子结点,左孩子,右孩子,完全二叉树,满二叉树
深度怎么求:logn+1
大顶堆和小顶堆的关系,和兄弟节点的值无关,只和父子节点有关
调整2个要点:
1.从最后一个非叶子节点子树开始从后向前调整
2.调整的时候顺序是从上向下
3.升序(大顶堆),降序(小顶堆)
堆排序具体实现代码:
static void HeapAdjust(int arr[], int start, int end)
//时间复杂度O(logn) 空间 复杂度O(1)
{
int tmp = arr[start];
for(int i=2*start+1; i<=end; i=i*2+1)
//i? 堆排序效率高体现在这里i=i*2+1
{
//1.左右孩子都存在
//2.只有左孩子,没有右孩子
if(i<end && arr[i] < arr[i+1])
//通过i<end保证右孩子存在,且arr[i] <arr[i+1]保证左孩子小于右孩子
{
i++;//这时候让i指向较大的右孩子下标
}
//if判断失败的话,要么没有右孩子,要么有右孩子但是左孩子比右孩子值大,所以i不需要 改变
if(arr[i] > tmp)//判断较大孩子节点的值是否比父节点的值大,大的话向上覆盖,不然 就找到了合适位置
{
arr[start] = arr[i]; start = i;
}
else
{
break;//左右孩子中较大的孩子值小于tmp
}
}
arr[start] = tmp;//有两种情况执行到这一行代码:1.触底 2.找到放tmp的合适位置
}
//堆排序的时间复杂度O(nlogn) 空间复杂度O(1) 不稳定
void HeapSort(int arr[], int len)
{
//assert
//2.调整为大顶堆
for(int i=(len-1-1)/2; i>=0; i--)//O(nlogn)
{
HeapAdjust(arr, i, len-1);
}
//第一个for循环走出来,这时已经为大顶堆了
int tmp = 0; for(int j=0; j<len-1; j++) //j指的是循环的次数(顶部数据和最后一个节点交换的次 数)//O(nlogn)
{//3.将顶部数据和最后一个节点进行了交换
tmp = arr[0];
arr[0] = arr[len-1-j];
arr[len-1-j] = tmp;//已经将顶部数据和最后一个节点进行了交换
//4.重复2.3操作
HeapAdjust(arr, 0, (len-1-j)-1);
}
}
三.桶排序
基数(桶)排序,低位优先,所有数据从地位开始,依次放入对应的10个桶内,再依次从桶中将数据取出(循环次数和最大值的位数有关),直到所有数据全部有序。
此时,完全有序。
循环的次数和最大值的位数有关
第七种排序算法:基数(桶)排序, 低位优先,所有数据从低(个)位开始,依次放入到对应的10个桶内(入队),再依次从桶中将数据依次取出(出队),直到所有数据全部有序。 循环的次数和最大值的位数有关。 时间复杂度O(dn) 空间复杂度O(n) 不稳定
基数(桶)排序具体实现代码:
//获取数组中最大值的位数
static int Get_Figure(int arr[], int len)
{
int max = 0;
for(int i=0; i<len; i++)
{
if(arr[i] > max)
{
max = arr[i];
}
}
int count = 0;
while(max != 0)
{
count++; max /= 10;
}
return count;
}
//获取n的第fin位的值
//1234,2 = 2
//234,0 = 4
//12345,4 = 1
//12345,7 = 0
static int Get_num(int n, int fin)
{
for(int i=0; i<fin; i++)
{
n = n / 10;
}
return n % 10;
//return n/(int)(pow((double)10, fin)) % 10;
}
static void Radix(int arr[], int len, int fin)
//二维数组 fin判断的依据,到底是 以什么位排序
//时间复杂度O(n) 空间复杂度O(n)
{
int bucket[10][20] = {0};
//桶
int num[10] = {0};
//对应的桶中有多少个有效值
//所有的数据都以fin位为依据,放到了桶内
for(int i=0; i<len; i++)
//数组的下标 从0开始放
{
int index = Get_num(arr[i], fin);
//获取arr[i]的fin位的值,找到对应的桶
bucket[index][num[index]] = arr[i];
//放到对用的桶中第num[index]位上
num[index]++;
//对应的桶中有效个数++
}
//从0-9桶内依次取值到arr里
int k = 0;
for(int i=0; i<10; i++)
//几号桶
{
for(int j=0; j<num[i]; j++)
//j桶中有效值个数
{
arr[k++] = bucket[i][j];
}
}
}
static void Radix_queue(int arr[], int len, int fin)
//时间复杂度O(n) 空间复 杂度O(n)
{
LQueue queArr[10];
for(int i=0; i<10; i++)
{
InitLQueue(&queArr[i]);
}
for(int i=0; i<len; i++)
{
int index = Get_num(arr[i], fin);
Push(&queArr[index], arr[i]);
}
int k = 0;
for(int i=0; i<10; i++)
{
while(!IsEmpty(&queArr[i]))
{
Pop(&queArr[i], &arr[k++]);
}
}
for(int i=0; i<10; i++)
{
Destroy(&queArr[i]);
}
}
void RadixSort(int arr[], int len)
//时间复杂度O(dn) 空间复杂度(n)稳定
{
//assert
int count = Get_Figure(arr, len);
for(int i=0; i<count; i++)
//循环的趟数,低位优先
{
Radix_queue(arr, len, i);
}
}
四. 快速排序
每次找到基准值,以基准值为分界线,将数据分成两块,左边的数据都比基准值小,右边的数据都比基准值大
规则:
1.从右向左找比基准值小的数据,找到后,向左挪动
2.从左向右找比基准值大的数据,找到后,向右挪动
3.重复1,2,直到left ==right,结束,将基准值放到arr[left] 或者arr[right]内
**第八种排序算法:**快速排序,越有序越慢,每次找到基准值,以基准值为分界线,将数据分成两块,左边的数据都比基准值小,右边的数据都比基准值大
规则:
1.从右向左找比基准值小的数据,找到后,向左挪动
2.从左向右找比基准值大的数据,找到后,向右挪动
3.重复1,2,直到left = right,结束,将基准值放到arr[left] 或者arr[right]内
缺点:越有序越慢,不稳定
快速排序具体实现代码:
static int Partition(int arr[], int left, int right)
{
int tmp = arr[left];
while (left < right)
//进来保证有两个值
{
while(left < right && arr[right] > tmp)
right--;
if(left == right)
{
break;
}
arr[left] = arr[right];
while(left < right && arr[left] <= tmp)
left++;
if(left == right)
{
break;
}
arr[right] = arr[left];
}
arr[left] = tmp;
//arr[right] = tmp; return left;
//return right; 因为此时left == right
}
static void Quick(int arr[], int left, int right)
{
//第一种优化:如果有效个数特别少,直接调用直接插入排序
//第二种优化:三数取中
//第三种优化:防止完全有序,自己打乱一下
/*if(left < right)
{
int midindex = Partition(arr, left, right);
if(left < midindex-1)
{
Quick(arr, left, midindex-1);
}
if(midindex+1 < right)
{
Quick(arr, midindex+1, right);
}
}*/
if(left < right)
{
int midindex = Partition(arr, left, right);
Quick(arr, left, midindex-1);
Quick(arr, midindex+1, right);
}
}
static void Quick_stack(int arr[], int left, int right)
{
stack<int> st;
if(left < right)
{
int midindex = Partition(arr, 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 q = st.top();
st.pop();
int p = st.top();
st.pop();
int midindex = Partition(arr, p, q);
if(p < midindex-1)
{
st.push(p);
st.push(midindex-1);
}
if(midindex+1 < q)
{
st.push(midindex+1);
st.push(q);
}
}
}
void QuickSort(int arr[], int len)
//时间复杂度O(nlogn) 空间复杂度O(1) 不稳定
{
//assert
Quick_stack(arr, 0, len-1);
}