七種基本排序思考
阿新 • • 發佈:2018-11-30
//插排 //穩定 //時間複雜度【最差情況】:O(n^2) //空間複雜度:O(1) void InsertSort(int array[], int size) { int key; int i, j; for (i = 1; i < size; i++){ key = array[i]; for (j = i - 1; j >= 0; j--){ if (key >= array[j]){ break; } else{ array[j + 1] = array[j]; } } array[j + 1] = key; } }
void _InsertSort(int array[], int size, int gap) { for (int g = 0; g < gap; g++){ int key; int i, j; for (i = gap + g; i < size; i += gap){ key = array[i]; for (j = i - gap; j >= 0; j -= gap){ if (key >= array[j]){ break; } else{ array[j + gap] = array[j]; } } array[j + gap] = key; } } } //希排 //1 不穩定 //2 時間複雜度【最差情況】: O(n^2) void ShellSort(int array[], int size) { int gap = size; while (1){ gap = gap / 3 + 1; _InsertSort(array, size, gap); if (gap == 1){ break; } } }
void Swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } //不穩定 //時間複雜度 O(n^2) //選擇排序1(每次選擇最大的放到最後) void SelectSort(int array[], int size) { //i代表每次還剩多少個數,當剩下一個數的時候,就不要移動了 for (int i = size; i > 1; i--){ int max = 0;//最大值下標 for (int j = 1; j < i; j++){ if (array[j] > array[max]){ max = j; } } Swap(array + max, array + i - 1); } } //選擇排序2(每次選擇最大的放到最後,同時選擇最小的放到最前邊) void SelectSrotOP(int array[], int size) { int left = 0, right = size - 1; while (left < right) { int min = left, max = left; for (int j = left + 1; j <= right; j++){ if (array[j] > array[max]){ max = j; } if (array[j] < array[min]){ min = j; } } Swap(array + left, array + min); //注意!!! if (max == left){//此時說明最大值下標就是left下標元素 max = min;//此時最大值已經被交換到下標為min了,所以max應該移到min處 } Swap(array + right, array + max); left++; right--; } }
void AdjustDown(int array[], int size, int root)
{
int left = 2 * root + 1;//左孩子下標
int right = 2 * root + 2;//右孩子下標
if (left >= size){
return;//沒有左孩子(右孩子也肯定沒有)
}
int max = left;
if (right < size && array[right] > array[left]){
max = right;
}//有孩子,判斷大孩子下標
if (array[root] >= array[max]){
return;//如果雙親節點大於大孩子,不用調整
}
Swap(array + root, array + max);//交換大孩子和雙親節點
AdjustDown(array, size, max);
}
void CreateHeap(int array[], int size)
{
//從最後一個非葉子節點
//不斷向下調整
for (int i = (size - 1) / 2; i >= 0; i--){
AdjustDown(array, size, i);
}
}
//堆排
//不穩定
//時間複雜度 O(N*logN)
void HeapSort(int array[], int size)
{
//1 建大堆(升序)(找最大值)
CreateHeap(array, size);
for (int i = 0; i < size - 1; i++){
Swap(&array[0], &array[size - 1 - i]);
AdjustDown(array, size - i - 1, 0);
}
}
//氣泡排序
//穩定
//時間複雜度 O(N^2)
void BubbleSort(int array[], int size)
{
for (int i = 0; i < size - 1; i++){
int isSorted = 1;
for (int j = 0; j < size - 1 - i; j++){
if (array[j] > array[j + 1]){
Swap(array + j, array + j + 1);
isSorted = 0;
}
}
if (1 == isSorted){
break;
}
}
}
//快排小的放左、大的放右【左右指標法】
//時間複雜度 O(N)
int Partition_01(int array[], int left, int right)//基準值的下標
{
int begin = left;//不是0
int end = right; //不是right-1
while (begin < end){
//如果基準值在最右邊,先動begin
while (begin < end && array[begin] <= array[right]){
begin++;//第二次比較左右下標,防止所有元素都小於基準值,
}
while (begin < end && array[end] >= array[right]){
end--;//第二次比較左右下標,防止所有元素都大於基準值,
}
Swap(array + begin, array + end);
}
Swap(array + begin, array + right);
return begin;//基準值
}
//快排
//時間複雜度 O(N*logN) 最壞情況就是單枝樹O(N^2)
//空間複雜度 O(logN) O(N)
//array [left, right]
//左閉右閉
void _QuickSort(int array[], int left, int right)
{
if (left >= right){
return;
}
int div = Partition_02(array, left, right);//基準值的下標
_QuickSort(array, left, div - 1); //[left, div-1]
_QuickSort(array, div + 1, right); //[div+1, right]
}
void QuickSort(int array[], int size)
{
_QuickSort(array, 0, size - 1);
}
//快排小的放左、大的放右【左右挖坑法】
//時間複雜度 O(N)
int Partition_02(int array[], int left, int right)
{
int begin = left;
int end = right;
int pivot = array[right];//pivot 存的就是基準值
while (begin < end){
while (begin < end && array[begin] <= pivot){
begin++;
}
array[end] = array[begin];//補右坑==挖左坑
while (begin < end && array[end] >= pivot){
end--;
}
array[begin] = array[end];//補左坑==挖右坑
}
array[begin] = pivot;
return begin;
}
//快排
//時間複雜度 O(N*logN) 最壞情況就是單枝樹O(N^2)
//空間複雜度 O(logN) O(N)
//array [left, right]
//左閉右閉
void _QuickSort(int array[], int left, int right)
{
if (left >= right){
return;
}
int div = Partition_02(array, left, right);//基準值的下標
_QuickSort(array, left, div - 1); //[left, div-1]
_QuickSort(array, div + 1, right); //[div+1, right]
}
void QuickSort(int array[], int size)
{
_QuickSort(array, 0, size - 1);
}
//快排小的放左、大的放右【前後指標】
//時間複雜度 O(N)
int Partition_03(int array[], int left, int right)
{
int div = left;
int cur = left;
while (cur < right){
if (array[cur] < array[right]){
Swap(array + cur, array + div);
div++;
}
cur++;
}
Swap(array + div, array + right);
return div;
}
//快排
//時間複雜度 O(N*logN) 最壞情況就是單枝樹O(N^2)
//空間複雜度 O(logN) O(N)
//array [left, right]
//左閉右閉
void _QuickSort(int array[], int left, int right)
{
if (left >= right){
return;
}
int div = Partition_03(array, left, right);//基準值的下標
_QuickSort(array, left, div - 1); //[left, div-1]
_QuickSort(array, div + 1, right); //[div+1, right]
}
void QuickSort(int array[], int size)
{
_QuickSort(array, 0, size - 1);
}
附加講解:(快排不穩定)
選擇基準值的方法:1)最邊上(最左、最右)
2)隨機
3)三數取中
void Merge(int array[], int left, int mid, int right, int *extra)
{
int left_i = left;
int right_i = mid;
int extra_i = left;
while (left_i < mid && right_i < right){
if (array[left_i] <= array[right_i]){
extra[extra_i++] = array[left_i++];
}
else{
extra[extra_i++] = array[right_i++];
}
}
while (left_i < mid){
extra[extra_i++] = array[left_i++];
}
while (right_i < right){
extra[extra_i++] = array[right_i++];
}
for (int i = left; i < right; i++){
array[i] = extra[i];
}
}
//歸併排序
//時間複雜度 O(N*logN)
//空間複雜度 O(N)
//array [left, right)
//左閉右開
void _MergeSort(int array[], int left, int right, int *extra)
{
if (left == right - 1){
return;//[0,1)
}
if (left >= right){
return;//區間沒有數了
}
int mid = left + (right - left) / 2;
_MergeSort(array, left, mid, extra);//[left, mid)//左邊排有序
_MergeSort(array, mid, right, extra);//[mid, right)//右邊排有序
Merge(array, left, mid, right, extra);//整體合併成有序
}
void MergeSort(int array[], int size)
{
int *extra = (int *)malloc(size * sizeof(int));
_MergeSort(array, 0, size, extra);//左閉右開
free(extra);
}
歸排穩定
總結: