排序 算法
回顾一下排序算法的实现,似乎有七种,现在熟悉的有四种:冒泡、插入、选择、快速。剩下的堆排序、归并等学明白了再更。
#include<iostream>
using std::endl;
using std::cin;
using std::cout;
void swap(int& a, int& b) { //两数互相交换
int temp = a;
a = b;
b = temp;
}
void bubble_sort(int nums[],int len){ //冒泡排序法
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len - i -1; j++) {
if (nums[j] > nums[j + 1]) { //从下标0开始,前一个和后一个比较,若前一个大,交换二者。始终保证后一个是最大的
swap(nums[j], nums[j + 1]);
}
}
cout << "------------------------------" << endl; //观察每次大循环后的变化,方便调试用,实际用的时候把这四行删了
for (int ix = 0; ix < len; ix++) {
cout << nums[ix] << endl;
}
}
}
void bubble_sort0(int nums[],int len){ //简单的交换排序
for (int i = 0; i < len-1; i++) {
for (int j = i+1; j < len-1; j++) {
if (nums[i] > nums[j]) {
swap(nums[i], nums[j]);
}
}
}
}
void bubble_sort1(int nums[],int len){ //冒泡排序
for (int i = 0; i < len-1; ++i) {
for (int j = len-1; j >=i; --j) {
if (nums[j] > nums[j+1]) {
swap(nums[j], nums[j + 1]);
}
}
}
}
int main()
{
int num[]={ 125, 21, 4, 58, 7, 42, 67, 19 };
int len= sizeof(num) / sizeof(num[0]); //求元素个数
bubble_sort(num, len);
cout << "------------------------------" << endl;
for (int ix = 0; ix < len; ix++) {
cout << num[ix] << endl;
}
return 0;
}
对代码进行说明;首先i代表对长度为len-i的数组进行寻找最大值放到最后sums[len-i-1]中(有个减一是因为数组下标从0开始),首先看第一次寻找的结果。 num[]={ 125, 21, 4, 58, 7, 42, 67, 19 }是原数组,num[]={ 21, 4, 58, 7, 42, 67, 19,125 }是第一次循环结束后的数组。
我们分析一下交换过程 i=0时。
125, 21, 4, 58, 7, 42, 67, 19 j=0时,sums[ j ]=sums[ 0 ]=125,sums[ j+1 ]=sums[ 1 ]=21,前一个比后一个大,交换,保证大的在后一个。结果如下一行
21, 125, 4, 58, 7, 42, 67, 19 同时 j=1时,sums[ j ]=sums[ 1 ]=125,sums[ j+1 ]=sums[ 2 ]=4,注意,在i = 0的时候交换了数据,所以sums[ 1 ]是125了。然后又是前一个比后一个大,交换,结果变成下一行。以此类推
21, 4, 125, 58, 7, 42, 67, 19
21, 4, 58,125, 7, 42, 67, 19
21, 4, 58, 7,125, 42, 67, 19
21, 4, 58, 7, 42,125, 67, 19
21, 4, 58, 7, 42, 67,125, 19
21, 4, 58, 7, 42, 67, 19, 125 j =7,不满足j<len-i-1 = 8-0-1=7。第一次大循环结束
从结果可以看到,第一次循环结束后,数组中的最大值已经找到并放到了数组最后sums[len-0-1]中。接下来只要对前len-1个数(下标从0到 len-2,刚好 j 从0到len-i-1 ,i=1)进行排序就可以了。直到i=len-1 退出循环,函数返回。数组就排好序了。
似乎外面的大循环可以用递归来代替?
最后结果图
接下来的插入、选择都比较简单,就不特别详细的说了,test_sort(int num[] , int len),insert_sort(int nums[], int len)的思想都是一样的。首先比较数组前两个元素,使数组的前两个元素有序(从小到大或从大到小),然后依次加入数组元素。每次加入都经过大小比较和交换数据来保证前i个元素是有序的。
#include<iostream>
using std::endl;
using std::cin;
using std::cout;
//两数互相交换
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//自己大一用到现在的,瞎捣鼓的不知道啥排序法,似乎就是插入?
void test_sort(int nums[], int len) {
for (int i = 1; i < len; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) { //<号是从大到小排序,>号是从小到大排序
swap(nums[j], nums[i);
}
}
cout << "------------------------------" << endl; //每次大循环后的变化
for (int ix = 0; ix < len; ix++) {
cout << nums[ix] << endl;
}
}
}
//插入排序
void insert_sort(int nums[], int len)
{
for (int i = 1; i < len; i++) {
for (int j = i; j > 0; j--) {
if (nums[j] < nums[j - 1]) {
swap(nums[j], nums[j - 1]);
}
}
cout << "------------------------------" << endl; //每次大循环后的变化
for (int ix = 0; ix < len; ix++) {
cout << nums[ix] << endl;
}
}
}
int main()
{
int num[8]={ 125, 21, 4, 58, 7, 42, 67, 19 };
int len= sizeof(num) / sizeof(num[0]);
test_sort(num, len);
//insert_sort(num, len);
cout << "------------------------------" << endl;
for (int ix = 0; ix < len; ix++) {
cout << num[ix] << endl;
}
return 0;
}
看一下test_sort(num, len);函数的中间结果。截了 前四次的结果,第一次i=1,前两个元素(sums[ 0 ]和 sums[ 1 ])从大到小拍好序。然后i=2,前3个元素从大到小拍好序。i=3、4、5 .......。最后到 i=len-1.所有的就都排好了。insert_sort(num, len);也可以自己输出查看。
选择排序感觉和冒泡类似,就是每次遍历数组把最小的找到放到遍历数组开头,每遍历一次就把遍历的起始位置加一。冒泡就是找最大的放在遍历数组末尾,同时数组终止位置减一。没啥可写的
#include<iostream>
using std::endl;
using std::cin;
using std::cout;
//两数互相交换
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//选择排序
void selection_sort(int nums[], int len)
{
for (int i = 0; i < len; i++) {
for (int j = i+1; j <len; j++) {
if (nums[j] < nums[i]) {
swap(nums[j], nums[i]);
}
}
cout << "------------------------------" << endl; //每次大循环后的变化
for (int ix = 0; ix < len; ix++) {
cout << nums[ix] << endl;
}
}
}
int main()
{
int num[8]={ 125, 21, 4, 58, 7, 42, 67, 19 };
int len= sizeof(num) / sizeof(num[0]);
selection_sort(num, len);
cout << "------------------------------" << endl;
for (int ix = 0; ix < len; ix++) {
cout << num[ix] << endl;
}
return 0;
}
快速排序的算法,说一下快速排序的思想。从数组中找一个数作为基准(一般就是数组第一个元素)。小于基准的数放到数组前面,大于基准的数放到数组后面。数组变成 小 |基准| 大。然后比基准小的数组成新的数组,继续用这种方法处理排序(基准是新数组的第一个元素)比基准大也是同样处理的。容易想到当基准前只有一个数则比基准小的部分排序完成,同理。当基准后只有一个数则比基准大的部分排序完成。这就是排序完成退出条件
算法大致是这样一个过程,首先我把第一个元素拿出来作为基准了。此时我的数组第一个元素的位置可以说为 “空” 。然后我从数组末尾(用right来表示下标)开始比较。
1、末尾值比基准小,交换开头(lift)和末尾(right)的元素。这时候末尾是基准。开头是比基准小的数。是不是比基准小的在基准前面吧,对吧
2、要是末尾比基准大呢,那就数组末尾(right)减一。和倒数第二个比较。直到交换一次或者已经比较到了最开始了(也就是第一个元素(基准)比后面的都小)。如果比较到了最开始了,那没说的,对基准后面的元素继续按着这个流程走,选基准------比较------分出大小。
说说交换了一次后该怎么做。交换完后。这时候末尾是基准。开头是比基准小的数。然后数组开头(lift)加一,比较数组第开头lift个元素和基准大小。也是两种情况。
1、lift比基准大。交换开头(lift)和末尾(right)的元素。这时候的开头(lift)是基准。末尾(right)是比基准大的数。是不是比基准大的在基准后面吧,对吧
2、lift比基准小。lift加一然后继续比较。直到交换了一次或者发现比较完了(lift==right)开头等于末尾了。如果开头等于末尾了。那就完成了完成一次大小分堆了。如果是交换 一次。那么这时候的开头(lift)是基准。末尾(right)是比基准大的数。right减一,继续比较。直到(lift=right)就代表以这个基准的大小分堆完成。
可能讲的不太好懂,举个例子 ,a={15,7,4,11,3,6} 选15为基准,lift=0 right=5(这两个都是下标)从末尾right开始找,6比15 小,交换。变成a={6,7,4,11,3,15} 。lift加一,7不比15 大。lift继续加一,加到right=4的时候,3还是不比15 大。lift继续加一,right=5=lift,好的,这次的以15 为基准的大小分堆完成。继续对基准前后的元素进行排序。发现基准后面没有,就不用排了。
对{6,7,4,11,3}处理,选6作为基准, lift=0 right=4,也是从末尾right开始找,3比6小,交换,变成{3,7,4,11,6},left加一,7比6大,交换,变成{3,6,4,11,7},right减一。11比6大,right继续减一,4比6 小,交换。变成{3,4,6,11,7},lift加一,此时lift=right=2。这次的以6 为基准的大小分堆完成。继续对基准前后的元素进行排序。直到发现基准前面只有一个数,则整个排序完成
#include<iostream>
using std::endl;
using std::cin;
using std::cout;
//快速排序
void quick_sort(int nums[], int _left, int _right) {
int left = _left;
int right = _right;
int temp = 0;
if (left < right) { //如果排序的元素至少有两个则开始排序,只有一个?直接返回了
temp = nums[left]; //待排序的第一个元素作为基准元素
while (left != right) { //从左右两边交替扫描,直到left = right
while (right > left && nums[right] >= temp) {
right--; //从右往左扫描,找到第一个比基准元素小的元素
}
nums[left] = nums[right]; //找到这种元素nums[right]后与nums[left]交换
while (left < right && nums[left] <= temp) {
left++; //从左往右扫描,找到第一个比基准元素大的元素
}
nums[right] = nums[left]; //找到这种元素nums[left]后,与nums[right]交换
}
nums[right] = temp; //基准元素归位
cout << "------------------------------" << endl;
for (int ix = _left; ix <= _right; ix++) {
cout << nums[ix] << endl;
}
quick_sort(nums, _left, left - 1); //对基准元素左边的元素进行递归排序
quick_sort(nums, right + 1, _right); //对基准元素右边的进行递归排序
}
}
int main()
{
int num[8]={ 125, 21, 4, 58, 7, 42, 67, 19 };
int len= sizeof(num) / sizeof(num[0]);
quick_sort(num, 0,len-1);
cout << "------------------------------" << endl;
for (int ix = 0; ix < len; ix++) {
cout << num[ix] << endl;
}
return 0;
}