最近遇到了排序,每次都是用快排,冒泡,很少用别的,这里总结下,加深下自己的印象
这种文章已经多到如XXX,所以大家就择优阅读,我会慢慢补充,后面加上复杂度分析以及一些实际案例!希望本帖我会继续做下去
前几天看到有人说,如何让你的代码变得更加吸引人,其中一个方法就是运用模板,以前不怎么用,这里我就把排序全部用模板实现
其实这不是什么难度上的考察,而是一个人编程习惯的考察,以后要多多注意
//时间紧迫,就先简单贴上插入排序和希尔排序,因为二者还是紧密联系,要理解希尔,首先要理解清楚插入排序的规则
1、插入排序
就是逐步扩大有序区,这里有序区我假定在数组前部分,所以我们遍历的时候就是从第一个元素开始,在这之前没有元素,所以a[0]有序 现在判断a[1],我们发现a[1]<a[0],然后用一个index专门向有序区遍历,直至找到改元素位置。
[4] 2 5 1
[4 2] 5 1 --->[2 4] 5 1
[2 4 5] 1 ----> [2 4 5] 1
[2 4 5 1] ---> [2 4 1 5] ---> [2 1 4 5 ] --->[1 2 4 5]
就是这么一个过程啦(代码见InsertSotr())
2、希尔排序
它的思想是希望能够减少移动次数,例如上题的1 ,我们发现移动次数太多了,如果能够先判断到远的元素,那么是不是有更好的呢?这里存在一个间隔因子
interval 至少要有等于1的时候,全部排序一次,具体解释后面再补充,大家可以问问谷歌度娘
//============================================================================
// Name : SortMethods.cpp
// Author : YLF
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <time.h>
using namespace std;
#define MAX 100
template<typename T>
void printSortedArr(T* arr, int num);
template<typename T>
void InsertSort(T* arr, int num);
template<typename T>
void ShellSort(T *arr, int num);
typedef double type;
int main() {
type input = 0;
type arr[MAX];
int num = -1;
while(true){
num++;
cin>>input;
if(input!=-1)
arr[num] = input;
else
break;
}
//InsertSort(arr, num);
ShellSort(arr, num);
return 0;
}
//插入排序
/**
* 前面的序列作为有序序列
*/
template<typename T>
void InsertSort(T* arr, int num){
int i = 0, j = 0;
for(i=0; i<num;i++){
j = i-1;
while(j>=0){
if(arr[j]>arr[j+1]){
T temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
j--;
}
}
printSortedArr(arr, num);
}
/**
* 希尔排序
*/
template<typename T>
void ShellSort(T *arr, int num){
int interval = 3;
int i = 0, j = 0;
for(;interval>0;interval--){//分块
for(i=0;i<(num+1)/interval;i++){//间隔interval分为同一块,所以遍历次数就是块数
for(j=0;j<num;j=j+interval){
int k = j - interval;
while(k>=0){
if(arr[k]>arr[k+interval]){
T temp = arr[k];
arr[k] = arr[k+interval];
arr[k+interval] = temp;
}
k -= interval;
}
}
}
}
printSortedArr(arr, num);
}
/*
* 打印数组函数
*/
template<typename T>
void printSortedArr(T* arr, int num){
int i=0;
for(i=0;i<num;i++)
cout<<arr[i]<<",";
cout<<endl;
}
3、选择排序
//2013.10.13 今天继续补充几个 ,先简单的开始把
选择排序和冒泡排序个人感觉还是蛮相似的,走一圈找个最大最小的换到有序区,然后再遍历,
虽然平均的时间复杂度都是O(N^2)
不过冒泡的最好情况可以达到O(N)(一次都没有交换表示顺序已经排好,所以遍历一次即可)
选择排序则还是O(n^2),而且选择排序是不稳定的,冒泡是稳定的,
不过正如在http://blog.csdn.net/ylf13/article/details/12620185
我在这道题解法上来看,选择排序也是一个挺好理解的算法,废话不多说了,这个看代码足够了
/**
* 选择排序
* 我这里每次循环都把最小的放到前面的有序区里
*/
template<typename T>
void SelectSort(T* arr, int num){
int i = 0;
int minIndex = 0;//记录最小值的Index
int sortedIndex = 0;//有序区与无序区边界
for(sortedIndex=0; sortedIndex<num-1;sortedIndex++){
minIndex = sortedIndex;
for(i=sortedIndex;i<num;i++){
if(arr[i] < arr[minIndex])
minIndex = i;
}
T temp = arr[sortedIndex];
arr[sortedIndex] = arr[minIndex];
arr[minIndex] = temp;
}
printSortedArr(arr,num);
}
4、冒泡排序
这个大家再熟悉不过了把。。就是每次比较,如果前面的更大,就前后交换,不断把最大的冒泡到顶上,这个思想很重要,这里冒泡是相邻相邻的比,大家想想
是否存在冗余或者没必要的比较,个人感觉(纯属个人的想法,可能有问题,大家仔细斟酌)堆排序也是一种冒泡,只不过它冒泡的时候精简了比较次数,使得算法
从O(N^2) ---> O(NlogN) 对于堆排序,下一个算法我就写,这个算法还是很值得大家考虑的,我觉得它的思想很好,可以派生出很多类似的算法,我也多多上网查查,
尽量写得完整点,好了,言归症状,不就一冒泡么。。。思想很重要
/**
* 冒泡排序
* 这里把最大的往上冒 Oooooooo
*/
template<class T>
void BubbleSort(T* arr, int num){
int i=0, j=0;
for(i=num-1;i>0;i--){
bool success = true;
for(j=0;j<i;j++){
if(arr[j] > arr[j+1]){
T temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
success = false;
}
}
//这一步是用来判断是否已经调整好了,如果提前就排序好就退出,不用继续了
if(success)
break;
}
printSortedArr(arr, num);
}
5、堆排序
这里对堆排序大家可以理解成是一种跨越式的冒泡。
先说下堆
推荐参考:http://blog.csdn.net/morewindows/article/details/6709644
堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。
二叉堆的定义
二叉堆是完全二叉树或者是近似完全二叉树。
二叉堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
堆其实是一种逻辑结构,而实际表示结构是数组
下面都以最大堆为例子
如图,上半部分就是一个逻辑结构,而我们实际表示是下图数组
堆的寻找过程就是先从20(15,5)这个分支找到最大值,然后在找出30(20,10)这个堆的最大值,这样我们就把最大值冒泡上来了,而以前我们是通过5和15比较,15在和10比较,然后和20比较,。。。这样存在很多多余比较次数,而堆排序这种逻辑结构很好的克服了,所以时间复杂度就成为o(N*logN)
http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html这篇文章也很推荐,他是把这种比较形式和选择排序进行比较
/*
* 堆排序
*/
template <typename T>
void HeapSort(T* arr, int num){
//初始化堆成为最大堆
int i=0;
int sortedIndex = num;
for(;sortedIndex>0;sortedIndex--){
for(i=sortedIndex/2-1;i>=0;i--){
maxHeap(arr, i, sortedIndex);
}
T temp = arr[0];
arr[0] = arr[sortedIndex-1];
arr[sortedIndex-1] = temp;
}
printSortedArr(arr,num);
}
template<typename T>
void maxHeap(T* a, int index, int num){
int i = index;
int j = 2*i + 1;
T temp = a[i];
while(j<num){
if(j+1 < num)
if(a[j]<a[j+1])
j++;
if(a[j]>temp)
a[i]= a[j];
else
break;
i = j;
j = 2*i +1;
}
a[i] = temp;
}
其实,如果换个角度,我们直接从数组来看
画的丑了点,大概就是这种过程
6、快速排序
【2013.10.17】
俗话说得好,贵在坚持 !!真TM难坚持。。。
今天碰巧写到快排了,赶紧过来补充下。。。
快排:时间复杂度
时间复杂度:O(n*lgn)
最坏:O(n^2)
空间复杂度:O(n*lgn)
不稳定。
快排原理如下:
首先找出个主元,就是作为中间比较元素
5 2 7 4 9 8
假设我们取a[0]=5作为主元,那么接下来就是和他比较,设两个指针i j一个指向头,另一个指向尾,
5 2 7 4 9 8 (主元)temp=5
i j
首先移动J if(arr[j] < temp) 由于我们的规则是,把比主元5小的放在数组前面,比主元5大的放在数组后面,那么 如果arr[j] 小于 temp,那么arr[i] = arr[j],这时候i++
否则就是j--,过程如下
5 2 7 4 9 8 (主元)temp=5
i j
5 2 7 4 9 8 (主元)temp=5
i j
好了,这时候4<5(主元)所以:4 2 7 4 9 8 (主元)temp=5
i j
然后i++ 注意绿色的4就是一个无效元素,等待被人取代
4 2 7 4 9 8 (主元)temp=5
i j
4 2 7 4 9 8 (主元)temp=5
i j
2还是小于5
4 2 7 4 9 8 (主元)temp=5
i j
这里7>5 所以
4 2 7 7 9 8 (主元)temp=5
i j
然后j--
4 2 7 7 9 8 (主元)temp=5
ij
判断i==j?? a[i] = temp4 2 5 7 9 8 (主元)temp=5
ij
好啦,然后采用分而治之的方法即可。。。void QuickSort(int* &arr, int l, int h){
int i = l;
int j = h;
int temp = arr[i];
while(i < j){
while(i<j && arr[j]>temp)
j--;
if(i<j){
arr[i] = arr[j];
i++;
}
while(i<j && arr[i]<temp)
i++;
if(i<j){
arr[j] = arr[i];
j--;
}
}
arr[i] = temp;
if(i-1>l)
QuickSort(arr,l,i-1);
if(i+1<h)
QuickSort(arr,i+1,h);
}
很多算法题目,给的是一些乱序的数组,要我们找出某个规律的东西,如果能排序下就会发现很多答案就呈现出来,一般排序后的算法复杂度都降为O(N)
例如:字母排序 http://blog.csdn.net/ylf13/article/details/12835037
数字排序http://blog.csdn.net/ylf13/article/details/12776639
1万+

被折叠的 条评论
为什么被折叠?



