912. 排序數(shù)組(c++)

題目描述: 給你一個(gè)整數(shù)數(shù)組 nums,將該數(shù)組升序排列。

上來(lái)的第一想法,居然就這么打卡成功了,哈哈哈哈哈哈哈哈

image

這個(gè)樣子是肯定不行滴,要進(jìn)步,就要自己親力親為,來(lái),研究一下排序算法

image

插入排序: 簡(jiǎn)單插入排序 ----- 希爾排序 平均時(shí)間復(fù)雜由n2降低為n1.3,最壞時(shí)間復(fù)雜度,最好時(shí)間復(fù)雜度n2和空間復(fù)雜度o1均未變。

交換排序:冒泡排序 ------ 快速排序 平均時(shí)間復(fù)雜度由n2降低為nlogn,最壞時(shí)間復(fù)雜度由n2降低為nlogn,最好時(shí)間復(fù)雜度有損失,由n變?yōu)閚logn,空間復(fù)雜度有損失,由n變?yōu)閚logn

選擇排序:簡(jiǎn)單選擇排序 ----- 堆排序 平均時(shí)間復(fù)雜度又n2降低為nlogn,最壞時(shí)間復(fù)雜度由n2降低為nlogn,最好時(shí)間復(fù)雜度由n2降低為nlogn,空間復(fù)雜度是O1沒(méi)有變化

//
// Created by Xue,Lin on 2020/6/18.
//
#ifndef UNTITLED_SORT_ALGORITHM_H
#define UNTITLED_SORT_ALGORITHM_H
void swap(int &a, int &b)
{
   // cout << "break3" << endl;
   int tmp = a;
   a = b;
   b = tmp;
}
// 希爾排序是插入排序,堆排序是選擇排序,冒泡排序和快速排序是交換排序

// 1.插入排序  穩(wěn)定,不占用額外空間,平均時(shí)間復(fù)雜度和最壞時(shí)間復(fù)雜度均為n2
// 思路為找到每個(gè)元素該在的位置,n輪循環(huán)后前n個(gè)元素有序,比較n+1元素和前n個(gè)元素
// 找到n+1元素應(yīng)在位置,插入,此時(shí)前n+1元素有序
// 兩輪循環(huán)
// 最壞時(shí)間復(fù)雜度n2,平均時(shí)間復(fù)雜度n2
// 最好情況為整個(gè)數(shù)組有序,每個(gè)元素僅需要和前一個(gè)元素比較,復(fù)雜度n
// 因此比較是個(gè)基本有序的數(shù)組
// 注意數(shù)組作為參數(shù)傳遞,一定要傳遞數(shù)組長(zhǎng)度,在函數(shù)內(nèi)無(wú)法判斷長(zhǎng)度
void insertSort(int a[10], int n)
{
   for(int i = 1; i < n; i++)
   {
       if (a[i] > a[i - 1])
       {
           continue;
       }
       for(int j = i - 1; j >= 0; j--)
       {
           if (a[j+1] < a[j])
           {
               swap(a[j+1], a[j]);
           } else
           {
               break;
           }
       }
   }
}

// 2.冒泡排序
// 注意是相鄰元素比較,如果想把最大的先撈出來(lái),第二重循環(huán)就從前往后遍歷
// 如果是想把最小的先撈出來(lái),第二重循環(huán)就從后往前遍歷
void bubbleSort(int a[], int n)
{
   for(int i = 0; i < n; i++)
   {
       for(int j = n; j >= i; j--)
       {
           if (a[j-1] > a[j])
           {
               swap(a[j-1], a[j]);
           }
       }
   }
}

// 3.快速排序,冒泡排序的升級(jí),屬于交換排序類
// 快速排序基本思想為通過(guò)一趟排序?qū)⒋判虻挠涗浄指畛蓛蓚€(gè)獨(dú)立的部分
// 其中一部分記錄的關(guān)鍵字均比另外一部分要小,然后對(duì)這兩部分進(jìn)行分別排序
// 最終實(shí)現(xiàn)整個(gè)數(shù)組有序
// partition是快排的精髓部分,交換原始表a中數(shù)據(jù)位置,使小于樞紐值在左,大于樞紐值在右,最終返回樞紐所在位置
int partition(int a[], int low, int high)
{
   // 樞紐值設(shè)定為帶排序數(shù)組第一個(gè)元素
   // 由于樞紐值的選取會(huì)影響快排效率,有改進(jìn)法為3數(shù)選取,即在待排序數(shù)組中任選3個(gè)數(shù),取中間數(shù)為樞紐
   int pivot_value = a[low];
   // 交換方式為low和high兩個(gè)指針移動(dòng),
   // 先移動(dòng)high,high--,當(dāng)high小于pivot,交換,然后開(kāi)始low++,當(dāng)low大于pivot,交換
   // 再移動(dòng)high,重復(fù)上面過(guò)程,知道low和high相遇,代表此時(shí)partition結(jié)束
   while(low < high)
   {
       // cout << "low:" << low << " " << "high:" << high << endl;
       // 注意high要是有效的
       while(low < high && a[high] >= pivot_value)
       {
           high--;
       }
       swap(a[high], a[low]);
       // 注意這里要判斷l(xiāng)ow < high 并且 a[low] 小于等于而不是小于,不然遇到相等的會(huì)一直出不去
       while(low < high && a[low] <= pivot_value)
       {
           low++;
       }
       swap(a[low], a[high]);
   }
   return low;
}
void quickSort(int a[], int low, int high)
{
   if (low >= high)
   {
       return;
   }
   int pivot;
   pivot = partition(a, low, high);
   quickSort(a, low, pivot - 1);
   quickSort(a, pivot + 1, high);
}
void quickSort(int a[], int n)
{
   quickSort(a, 0, n - 1);
}

// 4.歸并排序
// 歸并排序的原理是假設(shè)原始序列包含n個(gè)記錄,可以看成是n個(gè)有序的子序列,每個(gè)子序列的長(zhǎng)度為1
// 然后兩兩歸并,得到【n/2】個(gè)長(zhǎng)度為2的子序列,再兩兩歸并,直到整個(gè)序列有序
void merge(int a[], int begin, int mid, int end)
{
   cout << "begin: " << begin << "end: " << end << endl;
   int *arr = new int(end-begin);
   // 將a中begin到end按照從小到大歸并到arr,其中【begin,mid),【mid,end)是兩個(gè)有序子序列
   int l1 = begin, l2 = mid;
   int index = 0;
   while(l1 < mid && l2 < end)
   {
       if (a[l1] < a[l2])
       {
           arr[index] = a[l1];
           l1++;
       } else{
           arr[index] = a[l2];
           l2++;
       }
       index++;
   }
   while(l1 < mid)
   {
       arr[index++] = a[l1++];
   }
   while(l2 < end)
   {
       arr[index++] = a[l2++];
   }
   for(int i = begin; i < end; i++)
   {
       a[i] = arr[i-begin];
   }
   return;
}
void msort(int a[], int begin, int end)
{
   if (begin >= end - 1)
   {
       return;
   }
   int mid = begin + (end - begin) / 2;
   cout << "begin: " << begin << "end: " << end << "mid:" << mid << endl;
   msort(a, begin, mid);
   msort(a, mid, end);
   merge(a, begin, mid, end);
   return;
}
void mergeSort(int a[], int n)
{
   msort(a, 0, n);
}

// 5.堆排序
// 堆是具有以下性質(zhì)的完全二叉樹(shù):每個(gè)節(jié)點(diǎn)的值都大于或等于其左右孩子的節(jié)點(diǎn)值,稱為大頂堆
// 每個(gè)節(jié)點(diǎn)值都小于或等于其左右孩子的節(jié)點(diǎn)值,稱為小頂堆
// 堆排序就是利用堆進(jìn)行排序的方法。將待排序數(shù)組構(gòu)造成一個(gè)大頂堆,此時(shí),這個(gè)序列的最大值就是堆頂
// 將他移走(就是把堆頂和堆數(shù)組末尾元素交換,此時(shí)末尾元素就是最大值)
// 然后將剩余n-1個(gè)序列重新構(gòu)造一個(gè)堆,這樣就會(huì)得到n個(gè)元素中次大值
// 反復(fù)重復(fù),可以得到一個(gè)有序序列
// 所以核心是實(shí)現(xiàn)兩個(gè)函數(shù) 1.根據(jù)當(dāng)前序列構(gòu)建一個(gè)堆 2.在輸出堆頂元素后,如何調(diào)整剩余元素成為一個(gè)新堆
// 參考鏈接:https://www.cnblogs.com/wanglei5205/p/8733524.html
void headAdjust(int a[], int begin, int end)
{
   // 核心函數(shù),建立堆
   // begin為第一個(gè)非葉子節(jié)點(diǎn)的下標(biāo)
   // cout << "begin:" << begin << "end:" << end << endl;
   int temp, j;
   temp = a[begin];
   for(j = 2*begin; j < end - 1; j=j*2)
   {
       // 找到一個(gè)比較大的元素和當(dāng)前元素進(jìn)行交換
       if (j < end - 1 && a[j] < a[j+1])
       {
           j++;
       }
       if (temp >= a[j])
       {
           break;
       }
       a[begin] = a[j];
       begin = j;
   }
   a[begin] = temp;
   // cout << "begin:" << begin << "end:" << end << endl;
   return;
}
void headSort(int a[], int n)
{
   int i;
   // 兩個(gè)循環(huán)
   // 第一個(gè)循環(huán)根據(jù)序列建立一個(gè)堆
   for(i = n / 2; i >= 0; i--)
  {
       // cout << "break 1" << endl;
       // 從第一個(gè)非葉子節(jié)點(diǎn)開(kāi)始,當(dāng)前非葉子節(jié)點(diǎn)大頂堆,一步步往上推
       headAdjust(a, i, n);
   }
   /*  可以把樹(shù)結(jié)構(gòu)打出來(lái),驗(yàn)證問(wèn)題,打出來(lái)就是按每層從左到右
   for(int i = 0; i < n; i++)
   {
       cout << a[i] << " ";
   }
   */
   // 第二個(gè)循環(huán)為移除頂點(diǎn),然后重新建立堆
   for(i = n; i >= 1; i--)
   {
       // cout << "break2" << endl;
       swap(a[0], a[i-1]);
       // 這個(gè)時(shí)候因?yàn)榻粨Q了頂點(diǎn),因此頂點(diǎn)不滿足大頂堆,但是其余根節(jié)點(diǎn)還是滿足的
       // 因此這里begin參數(shù)傳0就可以
       headAdjust(a, 0, i-1);
       /*
       for(int i = 0; i < n; i++)
       {
           cout << a[i] << " ";
       }
       */
   }
   return;
}

// 6.希爾排序
// 希爾排序是插入排序的升級(jí),看好的是插入排序相對(duì)基本有序數(shù)組排序較為高效的特點(diǎn)
// 希爾排序的思想是,每次循環(huán)完成對(duì)間隔為increment數(shù)組的排序,直到increment為1,即為完成全數(shù)組排序
void shellSort(int a[], int n)
{
   int increment = n;
   do{
     increment = increment / 3 + 1;
     cout << increment << endl;
     for(int i = increment; i < n; i++)
     {
         // cout << "i:" << i << endl;
         int tmp = a[i];
         if (a[i - increment] > tmp)
         {
             // 尋找當(dāng)前tmp插入的最合適的位置,應(yīng)該插入到比他小的元素的前面,后面的元素都后移
             int j = i - increment;
             for( ; j >= 0 && tmp < a[j]; j-=increment)
             {
                 // cout << "j:" << j << endl;
                 // 后移
                 a[j+increment] = a[j];
             }
             // tmp插入合適位置
             a[j+increment] = tmp;
         }
         // 完成一次按間隔increment抽出來(lái)的數(shù)組的插入排序
     }
   } while(increment > 1);
}

#endif //UNTITLED_SORT_ALGORITHM_H
   int a[10] = {1,4, 2, 7, 2, 3, 8, 9, 4};
   // insertSort(a, 10);
   // bubbleSort(a, 10);
   // quickSort(a, 10);
   // shellSort(a, 10);
   // headSort(a, 10);
   mergeSort(a, 10);
   for(int i = 0; i < 10; i++)
   {
       cout << a[i] << " ";
   }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容