對現有工作並不是很滿意,所以決定找下一個坑。由工作中遇到排序場景並不多,大都是用冒泡排序,太low,面試又經常問到一些排序算法方面的東西。剛好讓小學妹郵的數據結構也到了。就把各種排序算法重新總結一下,以作留存。
排序分爲內部排序和外部排序,內部排序是在內存中排序。外部排序是由於排序記錄量太大,內存一次放不下全部記錄,排序過程中需要對外部存儲訪問的排序過程。外部排序用到的場景比較少,所以本次總結的都是內部排序。
排序安全:相同的元素相對位置不變,是排序安全,反之是不安全。
一,直接插入排序
基本思路:把一個元素插入到已排好的有序表中。(初始時認爲是隻有一個有序元素爲有序表和其他無序元素)
應用場景:基本有序時複雜度爲n。
是否排序安全:安全。
複雜度:O(n2).
代碼:
//直接插入排序
void CSort::InsertSort(int *a, int len)
{
for (int i = 1; i < len; i++)
{
int key = a[i];
int j = i - 1;
//當前元素做爲key
while (j>=0 && a[j] > key)
{
//不是元素應當插入時的位置,全部後移
a[j + 1] = a[j];
j--;
}
//插入元素到正確位置
a[j+1] = key;
}
}
二,希爾排序
希爾排序是直接插入排序的改進。
基本思路:先將整個待排序記錄按照增量分割成若干子序分別進行插入排序,基本有序時在進行一次直接插入排序。
實現:先使增量爲長度的一半,在讓增量變爲增量的一半,使序列逐漸有序,增量爲1時,等於對基本有序數列進行一次直接插入排序。
應用場景:基本有序時複雜度爲n。
是否排序安全:不安全。
複雜度:O(n2).
代碼:
//希爾插入,當增量爲1時就是直接插入排序
void CSort::ShellInsert(int *a, int len, int dk)
{
for (int i = dk + 1; i < len; i++)
{
int key = a[i];
int j = i - dk;
while (j >= 0 && a[j] > key)
{
a[j +dk] = a[j];
j -= dk;
}
a[j + dk] = key;
}
}
//希爾排序
void CSort::ShellSort(int *a, int len)
{
int k = len / 2;
while (k >= 1)
{
ShellInsert(a, len, k);
k = k / 2;
}
}
三,冒泡排序
基本思路:在要排序的一組數中,對當前還未排好序的範圍內的全部數,自上而下對相鄰的兩個數依次進行比較和調整,讓較大的數往下沉,較小的往上冒。即:每當兩相鄰的數比較後發現它們的排序與排序要求相反時,就將它們互換。
是否排序安全:安全
代碼:
void CSort::BubbleSort(int *a, int len){
for (int i = 0; i < len; i++)
{
for (int j = i + 1; j < len; j++)
{
if (a[i] > a[j])
{
swap(&a[i], &a[j]);
}
}
}
}
四,快速排序。(冒泡排序的優化)
基本思路:選取一個元素, 把表裏的元素依次對比選取的元素,分割成2個表(此時元素以在最終的位置)。在依次對這兩個表進行重複操作。次元素所在的位置就是最終其應該在的位置。當表裏的元素數量爲1時結束。
適用場景:快速排序是平均複雜度最低的排序。
是否排序安全:不安全
代碼:
//快速排序
int CSort::Partition(int *a, int low, int high)
{
int key = a[low];
while (low < high)
{
while (low < high&&a[high] >= key) high--;
swap(&a[low],&a[high]);
while (low < high&&a[low] <= key) low++;
swap(&a[low],&a[high]);
}
return low;
}
void CSort::QuickSort(int *a, int low, int high)
{
if (low<high)
{
int index = Partition(a, low, high);
QuickSort(a, low, index - 1);
QuickSort(a, index + 1, high);
}
}
五,選擇排序(簡單選擇排序)。
基本思路:每一趟循環都選擇最小(大)的元素作爲有序數列的第i個元素。
適用場景:
是否排序安全:不安全
代碼:
void CSort::SelectSort(int *a, int len){
for (int i = 0; i < len; i++)
{
int index = i;
for (int j = i + 1; j < len; j++)
{
if (a[j] < a[index])
{
index = j;
}
}
swap(&a[index],&a[i]);
}
}
六,歸併排序。
基本思路:歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分爲若干個子序列,每個子序列是有序的。然後再把有序子序列合併爲整體有序序列。
歸併排序示例:
複雜度:O(n)
使用場景:適用於很多元素而且無序的排序。
代碼:
void CSort::Merge(int *r, int *rf, int i, int m, int n)
{
int j, k;
for (j = m + 1, k = i; i <= m && j <= n; ++k){
if (r[j] < r[i]) rf[k] = r[j++];
else rf[k] = r[i++];
}
while (i <= m) rf[k++] = r[i++];
while (j <= n) rf[k++] = r[j++];
}
void CSort::MergeSort(int *r, int *rf, int lenght)
{
int len = 1;
int *q = r;
int *tmp;
while (len < lenght) {
int s = len;
len = 2 * s;
int i = 0;
while (i + len < lenght){
Merge(q, rf, i, i + s - 1, i + len - 1); //對等長的兩個子表合併
i = i + len;
}
if (i + s < lenght){
Merge(q, rf, i, i + s - 1, lenght - 1); //對不等長的兩個子表合併
}
tmp = q; q = rf; rf = tmp; //交換q,rf,以保證下一趟歸併時,仍從q 歸併到rf
}
}
下面附帶實現的全部源碼。
////////////////////////////////////////////////////////////
//
// SortTest.h
//
////////////////////////////////////////////////////////////
#ifndef __CSORT_TEST_H__
#define __CSORT_TEST_H__
#include <stdio.h>
#include <stdlib.h>
class CSort
{
public:
void swap(int *a,int *b);
//直接插入排序
void InsertSort(int *a, int len);
//希爾排序
void ShellInsert(int *a, int len, int dk/*增量*/);
void ShellSort(int *a,int len);
//快速排序
void QuickSort(int *a,int low,int high);
int Partition(int *a,int low,int high);
//選擇排序
void SelectSort(int *a,int len);
//冒泡排序
void BubbleSort(int *a,int len);
//歸併排序
void Merge(int *r, int *rf, int i, int m, int n);
void MergeSort(int *r, int *rf, int lenght);
};
#endif
////////////////////////////////////////////////////////////
//
// SortTest.cpp
//
////////////////////////////////////////////////////////////
#include "SortTest.h"
void CSort::swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//直接插入排序
void CSort::InsertSort(int *a, int len)
{
for (int i = 1; i < len; i++)
{
int key = a[i];
int j = i - 1;
while (j>=0 && a[j] > key)
{
a[j + 1] = a[j];
j--;
}
a[j+1] = key;
}
}
//希爾插入,當增量爲1時就是直接插入排序
void CSort::ShellInsert(int *a, int len, int dk)
{
for (int i = dk + 1; i < len; i++)
{
int key = a[i];
int j = i - dk;
while (j >= 0 && a[j] > key)
{
a[j +dk] = a[j];
j -= dk;
}
a[j + dk] = key;
}
}
//希爾排序
void CSort::ShellSort(int *a, int len)
{
int k = len / 2;
while (k >= 1)
{
ShellInsert(a, len, k);
k = k / 2;
}
}
//快速排序
int CSort::Partition(int *a, int low, int high)
{
int key = a[low];
while (low < high)
{
while (low < high&&a[high] >= key) high--;
swap(&a[low],&a[high]);
while (low < high&&a[low] <= key) low++;
swap(&a[low],&a[high]);
}
return low;
}
void CSort::QuickSort(int *a, int low, int high)
{
if (low<high)
{
int index = Partition(a, low, high);
QuickSort(a, low, index - 1);
QuickSort(a, index + 1, high);
}
}
void CSort::SelectSort(int *a, int len)
{
for (int i = 0; i < len; i++)
{
int index = i;
for (int j = i + 1; j < len; j++)
{
if (a[j] < a[index])
{
index = j;
}
}
swap(&a[index],&a[i]);
}
}
void CSort::BubbleSort(int *a, int len)
{
for (int i = 0; i < len; i++)
{
for (int j = i + 1; j < len; j++)
{
if (a[i] > a[j])
{
swap(&a[i], &a[j]);
}
}
}
}
void CSort::Merge(int *r, int *rf, int i, int m, int n)
{
int j, k;
for (j = m + 1, k = i; i <= m && j <= n; ++k){
if (r[j] < r[i]) rf[k] = r[j++];
else rf[k] = r[i++];
}
while (i <= m) rf[k++] = r[i++];
while (j <= n) rf[k++] = r[j++];
}
void CSort::MergeSort(int *r, int *rf, int lenght)
{
int len = 1;
int *q = r;
int *tmp;
while (len < lenght) {
int s = len;
len = 2 * s;
int i = 0;
while (i + len < lenght){
Merge(q, rf, i, i + s - 1, i + len - 1); //對等長的兩個子表合併
i = i + len;
}
if (i + s < lenght){
Merge(q, rf, i, i + s - 1, lenght - 1); //對不等長的兩個子表合併
}
tmp = q; q = rf; rf = tmp; //交換q,rf,以保證下一趟歸併時,仍從q 歸併到rf
}
}
int main()
{
CSort sort;
int a[10] = {10,20,32,13,9,25,23,45,56,1};
printf("\n排序前!");
for (size_t i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
//sort.InsertSort(a, 10);
//sort.ShellInsert(a, 10, 1);
//sort.ShellSort(a, 10);
//sort.QuickSort(a, 0, 9);
//sort.SelectSort(a, 10);
//sort.BubbleSort(a, 10);
int b[10] = { 0 };
sort.MergeSort(a,b,10);
printf("\n排序後!");
for (size_t i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("hello world!\n");
system("pause");
return 0;
}