排序
冒泡排序
void bubblesort(int a[], int n) { for(int i=0; i<n-1; i++) for(int j=0; j<n-1-i; j++) if(a[j]>a[j+1]) swap(a[j],a[j+1]); } //或者 void bubblesort(int a[], int n) { for(int i=0; i<n; i++) for(int j=i; j<n; j++) if(a[i]>a[j]) swap(a[i],a[j]); }
比较次数:1+2+......+N-1
优化版冒泡排序
- void bubblesort(int a[], int n) n2
- {
- bool flag = true;
- for(int i=0; i<n-1 &&falg; i++)
- {
- flag = false;
- for(int j=1; j<n-i; j++)
- if(a[j]<a[j-1])
- {
- swap(a[j],a[j-1]);
- flag = true;
- }
- }
- }
- /* 设置一个标志域flag,如果某一趟排序发生了变换,那么flag为true。
- * 如果某一趟排序没有发生交换,则说明序列已经有序了,不必再进行继续的比较操作,此时flag为false
- */
——————————————————————————————————————————————————————————
选择排序
思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
- void Selectsort(int a[], int n) n2
- {
- for(int i=0; i<n-1 ; i++)
- {
- min = i;
- for(int j=i+1; j<n; j++)
- if(a[min] > a[j])
- min = j;
- }
- if(min != i)
- {
- swap(a[min], a[i]);
- }
归并排序
- //将有序数组a[]和b[]合并到c[]中
- void MemeryArray(int a[], int n, int b[], int m, int c[]) nlog2n
- {
- int i, j, k;
- i = j = k = 0;
- while (i < n && j < m)
- {
- if (a[i] < b[j])
- c[k++] = a[i++];
- else
- c[k++] = b[j++];
- }
- while (i < n)
- c[k++] = a[i++];
- while (j < m)
- c[k++] = b[j++];
- }
可以看出合并有序数列的效率是比较高的,可以达到O(n)。
插入排序
如果a[j]前一个数据a[j-1] > a[j],就交换a[j]和a[j-1],再j--直到a[j-1] <= a[j]。这样也可以实现将一个新数据新并入到有序区间,从小到大排序。
- void Insertsort3(int a[], int n) n2
- {
- int i, j;
- for (i = 1; i < n; i++)
- for (j = i - 1; j >= 0 && a[j] > a[j + 1]; j--)
- Swap(a[j], a[j + 1]);
- }
快速排序
思想
快速排序采用的思想是分治思想。
快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。
举例说明一下吧,这个可能不是太好理解。假设要排序的序列为
2 2 4 9 3 6 7 1 5 首先用2当作基准,使用i j两个指针分别从两边进行扫描,把比2小的元素和比2大的元素分开。首先比较2和5,5比2大,j左移
2 2 4 9 3 6 7 1 5 比较2和1,1小于2,所以把1放在2的位置
2 1 4 9 3 6 7 1 5 比较2和4,4大于2,因此将4移动到后面
2 1 4 9 3 6 7 4 5 比较2和7,2和6,2和3,2和9,全部大于2,满足条件,因此不变
经过第一轮的快速排序,元素变为下面的样子
[1] 2 [4 9 3 6 7 5]
之后,在把2左边的元素进行快排,由于只有一个元素,因此快排结束。右边进行快排,递归进行,最终生成最后的结果。
代码
int quicksort(int a[], int left, int right){
if(left >= right){ return; }
int key = a[left];
int low = left;
int high = right;
while(low < high)
{
while(low < high && a[high] > key)
{
high--;
}
a[low] = a[high];
while(low < high && a[low] < key)
{
low++;
}
a[high] = a[low];
}
a[low] = key;
quicksort(a,left,low-1);
quicksort(a,low+1,right);
}
eg: 从一个含有10万个不同数据且任意存放的数组中找出10个最大的数?
- if (low + 1 > num) //当对照元素以及其右边的数据的个数大于要找的个数时,对照元素的大的那一边继续找num个数
- {
- Quicksort(a, left, low - 1, num);
- }
- if (low + 1 < num) //当对照元素以及其右边的数据的个数少于要找的个数时,对照元素的小的那一边继续找num-low-1个数
- {
- Quicksort(a, low + 1, right, num - low - 1);
- }
- return;
- }
分析
快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。
最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)
在最好情况下,每次划分所取的基准都是当前无序区的"中值"记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)
尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。
讲解:https://zhidao.baidu.com/question/498320427100370484.html
通俗的说:找到一个基准值,从右边找比它小的,如果是互换
从左边找比它大的,如果是互换
如果不符合了,第一轮结束,此时左右两边都重复执行如上操作
堆排序
http://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html
http://www.cnblogs.com/skywang12345/p/3602162.html
其基本思想为(大顶堆):
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无须区;
2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
void HeapAdject(int H[], int start, int end) { int temp=H[start]; for(int i=2*start+1; i<=end; i*=2) //假设根结点的序号为0(不是1),所以i结点左孩子和右孩子分别为2i+1和2i+2 { if(i<end && H[i]<H[i+1]) //左右孩子的比较 { ++i; //i为较大的记录的下标 } if(temp>H[i]) //左右孩子中获胜者与父亲的比较 break; H[start] = H[i]; //将孩子结点上位,则以孩子结点的位置进行下一轮的筛选 start = i; } H[start]=temp; } void HeapSort(int a[], int n) { for(int i=n/2; i>=0; i--) //先建立大顶堆 { HeapAdjust(A,i,n); } for(int i=n-1; i>0; i--) //进行排序,最后一个元素和第一个元素进行交换 { swap(a[i], a[0]); HeapAdjust(A,0,i-1); //将剩下的元素继续进行调整排序 } }
eg:从一个含有10万个不同数据且任意存放的数组中找出100个最大的数?
先取出前100个数,维护一个100个数的最小堆,遍历一遍剩余的元素,在此过程中维护堆就可以了。具体步骤如下:
补充:这个方法的说法也可以更简化一些:
假设数组arr保存100个数字,首先取前100个数字放入数组arr,对于第101个数字k,如果k大于arr中的最小数,则用k替换最小数,对剩下的数字都进行这种处理。