数据结构与算法之排序(你不得不知道的排序算法)

数据结构与算法之排序(经典排序算法)

1、冒泡排序

代码分析:

这段代码实现了冒泡排序算法,其时间复杂度为 O ( n 2 ) O(n^2) O(n2)。冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换的元素,也就是说该数列已经排序完成。

在这段代码中,bubbleSort函数中的外层循环执行了n次,内层循环执行了n-1次,因此总的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。虽然冒泡排序的时间复杂度较高,但是它实现简单,对于小规模的数据排序效果还是不错的。

代码解读:

这段代码实现了冒泡排序算法。冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换的元素,也就是说该数列已经排序完成。

在这段代码中,swap函数实现了两个元素的交换,bubble函数实现了一次冒泡排序,bubbleSort函数则是对整个数组进行冒泡排序。其中,bubble函数返回一个布尔值,表示是否进行了交换操作,如果没有进行交换操作,说明数组已经排好序了,可以直接退出循环。

在main函数中,首先输出了原始数组,然后调用bubbleSort函数对数组进行排序,最后输出排序后的数组。可以看到,排序后的数组是按照从小到大的顺序排列的。

值得注意的是,这段代码中使用了模板类,可以对不同类型的数组进行排序。同时,使用了STL中的foreach函数,可以方便地对数组进行遍历输出。

#include <iostream>
#include <algorithm>

template<class T>
void swap (T& a, T& b)
{
    T temp = a;
    a = b;
    b = temp;
}

template<class T>
bool bubble (T a[], int n)
{
    bool swapped = false;
    for (int i = 0; i < n - 1; ++i)
    {
        if (a[i] > a[i+1])//如果数组已经是排序的话,则排序就终止了
        {
            swap(a[i], a[i+1]);
            swapped = true;
        }
    }
    return swapped;
}

template<class T>
void bubbleSort(T a[], int n)
{
    for (int i = n; i > 1 && bubble(a, i); --i); //最后只剩一个数字就是排好序的,故到a>1即可
}
void Show(const int& v)
{
    std::cout << v << " ";
}

int main()
{
    int arr[]{ 6, 5, 8, 4, 3, 1 };
    for (auto x : arr)
        std::cout << x << " ";
    //std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    std::cout << "\n";
    bubbleSort(arr, sizeof(arr) / sizeof(int));
    std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    std::cout << std::endl;
    return 0;
}

2、桶排序

#include<iterator>
#include<iostream>
#include<vector>
using std::vector;

/*****************
桶排序:将值为i的元素放入i号桶,最后依次把桶里的元素倒出来。
桶排序序思路:
1. 设置一个定量的数组当作空桶子。
2. 寻访序列,并且把项目一个一个放到对应的桶子去。
3. 对每个不是空的桶子进行排序。
4. 从不是空的桶子里把项目再放回原来的序列中。
假设数据分布在[0,100)之间,每个桶内部用链表表示,在数据入桶的同时插入排序,然后把各个桶中的数据合并。
*****************/


const int BUCKET_NUM = 10;

struct ListNode{
    explicit ListNode(int i=0):mData(i),mNext(NULL){}
    ListNode* mNext;
    int mData;
};

ListNode* insert(ListNode* head,int val){
    ListNode dummyNode;
    ListNode *newNode = new ListNode(val);
    ListNode *pre,*curr;
    dummyNode.mNext = head;
    pre = &dummyNode;
    curr = head;
    while(NULL!=curr && curr->mData<=val){
        pre = curr;
        curr = curr->mNext;
    }
    newNode->mNext = curr;
    pre->mNext = newNode;
    return dummyNode.mNext;
}


ListNode* Merge(ListNode *head1,ListNode *head2){
    ListNode dummyNode;
    ListNode *dummy = &dummyNode;
    while(NULL!=head1 && NULL!=head2){
        if(head1->mData <= head2->mData){
            dummy->mNext = head1;
            head1 = head1->mNext;
        }else{
            dummy->mNext = head2;
            head2 = head2->mNext;
        }
        dummy = dummy->mNext;
    }
    if(NULL!=head1) dummy->mNext = head1;
    if(NULL!=head2) dummy->mNext = head2;

    return dummyNode.mNext;
}

void BucketSort(int n,int arr[]){
    vector<ListNode*> buckets(BUCKET_NUM,(ListNode*)(0));
    for(int i=0;i<n;++i){
        int index = arr[i]/BUCKET_NUM;
        ListNode *head = buckets.at(index);
        buckets.at(index) = insert(head,arr[i]);
    }
    ListNode *head = buckets.at(0);
    for(int i=1;i<BUCKET_NUM;++i){
        head = Merge(head,buckets.at(i));
    }
    for(int i=0;i<n;++i){
        arr[i] = head->mData;
        std::cout << arr[i] << " ";
        head = head->mNext;
    }
    std::cout << std::endl;
}


int main()
{
    int a[] = {56, 89, 24, 6, 18, 5, 1, 99, 63};
    BucketSort(sizeof(a)/sizeof(int), a);
    return 0;
}

3、插入排序

#include <iostream>
#include <algorithm>
template<class T>
void insert(T a[], int n, const T& x)
{
    int i;
    for (i = n - 1; i >= 0 && x < a[i]; --i)
        a[i + 1] = a[i];
    a[i + 1] = x;//因为退出for循环之后i已经减了1
}

template<class T>
void insertionSort(T a[], int n)
{
    for (int i = 1; i < n; ++i)
    {
        T t = a[i];
        insert(a, i, t);//依次插入到恰好比下一个数字小的地方
    }
}

void Show(const int& v)
{
    std::cout << v << " ";
}

int main()
{
    int arr[]{ 6, 5, 8, 4, 3, 1 };
    for (auto x : arr)
        std::cout << x << " ";
    //std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    std::cout << "\n";
    insertionSort(arr, sizeof(arr) / sizeof(int));
    std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    std::cout << std::endl;
    return 0;
}

4、归并排序

递归版:

//完整代码

#include <iostream>

using namespace std;

template<typename T>
void merge_sort_recursive(T arr[], T reg[], int start, int end) {
    if (start >= end)
        return;
    int len = end - start, mid = (len >> 1) + start;
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    merge_sort_recursive(arr, reg, start1, end1);
    merge_sort_recursive(arr, reg, start2, end2);
    int k = start;
    while (start1 <= end1 && start2 <= end2)
        reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
    while (start1 <= end1)
        reg[k++] = arr[start1++];
    while (start2 <= end2)
        reg[k++] = arr[start2++];
    for (k = start; k <= end; k++)
        arr[k] = reg[k];
}
//整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)的運算子功能
template<typename T>
void merge_sort(T arr[], const int len) {
    T *reg = new T[len];
    merge_sort_recursive(arr, reg, 0, len - 1);
    delete[] reg;
}
void showAges(const int& age)
{
    std::cout << age << '\t';
}
void Test1()
{
    int ages[] = { 10, 9, 45, 30, 28, 90, 38, 30, 30, 45, 45 };
    merge_sort(ages, sizeof(ages) / sizeof(int));
    std::cout << "The sorted ages is:\n";
    for (auto x : ages)
        showAges(x);
    //    std::cout << x << '\t';

}
int main()
{
    Test1();
    return 0;
}

迭代版:

//完整代码

#include <iostream>

using namespace std;

/*****************
    迭代版
*****************/
//整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)的運算子功能
template<typename T>
void merge_sort(T arr[], int len) {
    T* a = arr;
    T* b = new T[len];
    for (int seg = 1; seg < len; seg += seg) {
        for (int start = 0; start < len; start += seg + seg) {
            int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        T* temp = a;
        a = b;
        b = temp;
    }
    if (a != arr) {
        for (int i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    delete[] b;
}

void showAges(const int& age)
{
    std::cout << age << '\t';
}
void Test1()
{
    int ages[] = { 10, 9, 45, 30, 28, 90, 38, 30, 30, 45, 45 };
    merge_sort(ages, sizeof(ages) / sizeof(int));
    std::cout << "The sorted ages is:\n";
    for (auto x : ages)
        showAges(x);
    //    std::cout << x << '\t';

}
int main()
{
    Test1();
    return 0;
}

5、快速排序

#include <iostream>
#include <algorithm>
#include <exception>
#include <cstdlib>
#include <ctime>//time
template<class T>
void swap(T* a, T* b)//注意用指针构造交换函数时,交换的是指针指向的值
{
    T temp = *a;
    *a = *b;
    *b = temp;
}
int RandomInRange(int st, int en)
{
    srand(unsigned(time(0)));//把当前时间作为随机数种子
    return st + rand() % (en - st + 1);
}
int Partition(int data[], int length, int start, int end)
{
    if (data == nullptr || length <= 0 || start < 0 || end >= length)
    {
        throw "Invalid Parameters";
    }
    int index = RandomInRange(start, end);
    swap(&data[index], &data[end]);
    int small = start - 1;
    for (index = start; index < end; ++index)
    {
        if (data[index] < data[end])//当条件不成立时index增加,small不变
        {
            ++small;
            if (small != index)
                swap(&data[index], &data[small]);
        }
    }
    ++small;
    swap(&data[small], &data[end]);
    return small;//返回的结果是左边比data[end]小,右边比data[end]大的数
}

void QuickSort(int data[], int length, int start, int end)
{
    if (start == end)
        return;
//**********************************这部分是判断数组是否已经按升序排好序,排好的话就直接终止,这样就防止出现最糟糕的情况
    bool sorted = true;   //《剑指offer》p81
    for (int i = start; i < end; ++i)
    {
        if (data[i] > data[i + 1])//如果数组已经是排序的话,则排序就终止了
        {
            sorted = false;
        }
    }
    if (sorted)
        return;
//****************************************************************************************
    int index = Partition(data, length, start, end);
    if (index > start)
        QuickSort(data, length, start, index - 1);
    if (index < end)
        QuickSort(data, length, index + 1, end);
}

void Show(const int& v)
{
    std::cout << v << " ";
}

int main()
{
    int arr[]{ 6, 5, 8, 4, 3, 1 };
    for (auto x : arr)
        std::cout << x << " ";
    //std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    std::cout << "\n";
    QuickSort(arr, sizeof(arr) / sizeof(int), 0, sizeof(arr) / sizeof(int) - 1);
    std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    return 0;
}

6、选择排序

#include <iostream>
#include <algorithm>
template<class T>
void swap (T& a, T& b)
{
    T temp = a;
    a = b;
    b = temp;
}
template<class T>
void selectionSort(T a[], int n)
{
    bool sorted = false;
    for (int size = n; !sorted && (size > 1); size--)
    {
        int indexOfMax = 0;
        sorted = true;
        for (int i = 1; i < size; ++i)
        {
            if (a[indexOfMax] <= a[i])
                indexOfMax = i;
            else
                sorted = false;//无序的
        }
        swap (a[indexOfMax], a[size - 1]);//如果是无序的,则每次循环将最大值放在最后一位
    }
}


void Show(const int& v)
{
    std::cout << v << " ";
}

int main()
{
    int arr[]{ 6, 5, 8, 4, 3, 1 };
    for (auto x : arr)
        std::cout << x << " ";
    //std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    std::cout << "\n";
    selectionSort(arr, sizeof(arr) / sizeof(int));
    std::for_each(arr, arr + sizeof(arr) / sizeof(int), Show);
    return 0;
}

桶排序的一个示例(《剑指offer》中的一个问题)

后面会补充剑指offer相关的内容

#include <iostream>
#include <exception>

void SortAges(int ages[], int length)
{
	if (ages == nullptr || length <= 0)
		return;
	const int oldestAge = 99;
	int timesOfAge[oldestAge + 1];
	for (int i = 0; i < oldestAge; ++i)
		timesOfAge[i] = 0;
	for (int i = 0; i < length; ++i)
	{
		int age = ages[i];
		if (age < 0 || age > oldestAge)
			throw new std::exception("age out og range");
		++timesOfAge[age];
	}
	int index = 0;
	for (int i = 0; i <= oldestAge; ++i)
	{
		for (int j = 0; j < timesOfAge[i]; ++j)
		{
			ages[index] = i;
			++index;
		}
	}
}
void showAges(const int& age)
{
	std::cout << age << '\t';
}
void Test1()
{
	int ages[] = { 10, 9, 45, 30, 28, 90, 38, 30, 30, 45, 45 };
	SortAges(ages, sizeof(ages) / sizeof(int));
	std::cout << "The sorted ages is:\n";
	for (auto x : ages)
		showAges(x); 
	//	std::cout << x << '\t';
	
}
int main()
{
	Test1();
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑着的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值