【C++面试】常考题复习:排序算法
// Sort.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h> /************************************************************************/
/* copyright (c) 2014 kernel_main
/* c++面试常考点
/* 转载请注明出处:http://www.cnblogs.com/kernel0815/
/************************************************************************/ //交换两个数
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
} #define PrintList(list, count) do\
{\
for (int i=;i<count;i++)\
{\
printf("%d ", list[i]);\
}\
\
printf("\r\n");\
}while(); //1. 冒泡排序
/*
算法原理:
冒泡排序算法的运作如下:(从后往前)
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
*/
void BubbleSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__);
PrintList(list, count); for (int i=; i<count-; i++)
{
for (int j=count-; j>i; j--)
{
if (list[j-] > list[j])
{
swap(list[j-], list[j]);
}
} PrintList(list, count);
}
} //2. 选择排序
/*
对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,
接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素
进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,
我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,
就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。
*/
void SelectSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__);
PrintList(list, count); int i, j, min_index, tmp; for (i=; i<count-; i++)
{
tmp = list[i];
min_index = i;
for (j=i+; j<count; j++)
{
if (list[j] < tmp)
{
tmp = list[j];
min_index = j;
}
} if (min_index != i)
{
swap(list[i], list[min_index]);
} PrintList(list, count);
}
} //3. 插入排序
/*
⒈ 从第一个元素开始,该元素可以认为已经被排序
⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⒌ 将新元素插入到下一位置中
⒍ 重复步骤2~5
如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。
*/
void InsertSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__);
PrintList(list, count); int i, j, tmp; for (i=; i<count; i++)
{
if (list[i-] > list[i])
{
tmp = list[i];
for (j=i-; j>= && list[j] > tmp; j--)
{
list[j+] = list[j];
}
list[j+] = tmp;
}
PrintList(list, count);
}
} //4. 快速排序
/*
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j;
(3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,
使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。
另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
*/
int PartSort(int* list, int lowIndex, int highIndex)
{
int tmp = list[lowIndex]; while(lowIndex < highIndex)
{
while(lowIndex < highIndex && list[highIndex] >= tmp)
{
highIndex--;
} swap(list[lowIndex], list[highIndex]); while(lowIndex < highIndex && list[lowIndex] <= tmp)
{
lowIndex++;
} swap(list[lowIndex],list[highIndex]);
} PrintList(list, ); return lowIndex;
} void QSort(int *list, int lowIndex, int highIndex)
{
int tmpIndex = ;
if (lowIndex < highIndex)
{
tmpIndex = PartSort(list,lowIndex, highIndex);
QSort(list, lowIndex, tmpIndex-);
QSort(list, tmpIndex+, highIndex);
}
} void QuickSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__);
PrintList(list, ); QSort(list, , count-);
} //5. 堆排序
/*
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
(2)大根堆排序算法的基本操作:
① 初始化操作:将R[1..n]构造为初始堆;
② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。
注意 ①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止
特点 堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录
区别 直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。
*/
void HeapAdjust(int* list, int s, int m)
{
int temp = list[s];
for(int j=*s+;j<=m;j = *j+)
{
if(list[j]<list[j+]&&j<m)
{
j++;
}
if(temp>list[j])
break;
list[s] = list[j];
s = j;
}
list[s] = temp;
} void HeapSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__); //创建一个大顶堆
for(int s = count/-;s>=;s--)
{
HeapAdjust(list,s,count-);
} //排序
for(int i = count-;i >= ;i--)
{
swap(list[],list[i]);
HeapAdjust(list,,i-); PrintList(list, );
}
} //6. shell排序
/*
希尔排序属于插入类排序,是将整个有序序列分割成若干小的子序列分别进行插入排序。
排序过程:先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;然后取d2<d1,重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止。
*/
void ShellSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__); int i,j;
int temp;
int increment = count;
do
{
increment = increment/+;
for(i = increment;i<count;i++)
{
if(list[i]<list[i-increment])
{
temp = list[i];
for(j=i-increment;j>=&&list[j]>temp;j-=increment)
{
list[j+increment] = list[j];
}
list[j+increment] = temp;
} PrintList(list, );
} }while(increment>);
} //7. 归并排序
/*
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
*/
//将有个有序数组排序
void Merge(int *list,int start,int mid,int end)
{
const int len1 = mid -start +;
const int len2 = end -mid;
const int len = end - start +;
int i,j,k; int * front = (int *)malloc(sizeof(int)*len1);
int * back = (int *)malloc(sizeof(int)*len2); for(i=;i<len1;i++)
front[i] = list[start+i];
for(j=;j<len2;j++)
back[j] = list[mid+j+]; for(i=,j=,k=start;i<len1&&j<len2&&k<end;k++)
{
if(front[i]<back[j])
{
list[k] = front[i];
i++;
}else
{
list[k] = back[j];
j++;
}
} while(i<len1)
{
list[k++] = front[i++];
} while(j<len2)
{
list[k++] = back[j++];
}
} //归并排序
void MSort(int *list,int start, int end)
{
if(start<end)
{
int mid = (start+end)/;
MSort(list,,mid);
MSort(list,mid+,end);
Merge(list,start,mid,end); PrintList(list, );
}
} void MergeSort(int* list, int count)
{
printf("===[%s]==\n", __FUNCTION__);
MSort(list,,count-);
} #define INT_ARR {3,5,9,2,7,6,1,8,0,4}
int _tmain(int argc, _TCHAR* argv[])
{
int list1[] = INT_ARR;
int list2[] = INT_ARR;
int list3[] = INT_ARR;
int list4[] = INT_ARR;
int list5[] = INT_ARR;
int list6[] = INT_ARR;
int list7[] = INT_ARR; BubbleSort(list1, );
SelectSort(list2, );
InsertSort(list3, );
QuickSort(list4, );
HeapSort(list5, );
ShellSort(list6, );
MergeSort(list7, ); return ;
}
【C++面试】常考题复习:排序算法的更多相关文章
- 面试常考各类排序算法总结.(c#)
前言 面试以及考试过程中必会出现一道排序算法面试题,为了加深对排序算法的理解,在此我对各种排序算法做个总结归纳. 1.冒泡排序算法(BubbleSort) 1.1 算法描述 (1)比较相邻的元素.如果 ...
- 【PHP面试题】通俗易懂的两个面试必问的排序算法讲解:冒泡排序和快速排序
又到了金三银四找工作的时间,相信很多开发者都在找工作或者准备着找工作了.一般应对面试,我们无可厚非的去刷下面试题.对于PHPer来说,除了要熟悉自己所做的项目,还有懂的基本的算法.下面来分享下PHP面 ...
- 【C++面试】常考题复习
// CPP_Test@2014.10.22.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <assert.h&g ...
- java面试常考题
基础知识: 1.C++或Java中的异常处理机制的简单原理和应用. 当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常.违反语义规则包括2种情况.一种是JAVA类库 ...
- Sql面试常考题(持续添加)
最近萌生换工作的念头,于是上网下载了一些公司的面试题,重新看了面试题中的Sql部分,这些查询题有时候只是兜一个弯角来考,对于给EF惯坏的孩子来说还是有点难度的(给面试官鄙视了几下的结果),所以列出最近 ...
- leetcode Two Sum II - Input array is sorted <面试常考题>
题目描述 //二分查找的变形 用头尾两个指针进行 面试考察题 class Solution { public: vector<int> twoSum(vector<int> ...
- 前端一面/面试常考题1-页面布局:假设高度已知,请写出三栏布局,其中左栏、右栏宽度各为300px,中间自适应。
题目:假设高度已知,请写出三栏布局,其中左栏.右栏宽度各为300px,中间自适应. [题外话:日常宣读我的目标===想要成为一名优雅的程序媛] 一.分析 1. 题目真的像我们想得这么简单吗? 其实不然 ...
- 六种排序算法的JavaScript实现以及总结
最近几天在系统的复习排序算法,之前都没有系统性的学习过,也没有留下过什么笔记,所以很快就忘了,这次好好地学习一下. 首先说明为了减少限制,以下代码通通运行于Node V8引擎而非浏览器,源码在我的Gi ...
- PHP面试常考之会话控制
你好,是我琉忆,欢迎您来到PHP面试专栏.本周(2019.2-25至3-1)的一三五更新的文章如下: 周一:PHP面试常考之会话控制周三:PHP面试常考之网络协议周五:PHP面试常考题之会话控制和网络 ...
随机推荐
- D触发器
普通的电路,以及常规的逻辑门都有一个共性,那就是输出直接依赖于输入,当输入消失的时候,输入也跟着不存在了.触发器不同,当它触发的时候,输出会发生变化.但是,当输入撤销之后,输出依然能够维持. 这就是说 ...
- 区分listview的item和Button的点击事件
这两天修改领导通的ListView widget,在ListView中加入Button这类的有 “点击” 事件的widget,发现原来listview的itemclick居然失效了, 后来在网上查资料 ...
- centos下yum安装wget失败
执行了yum -y install wget后得到下面的提示 Failed to set locale, defaulting to C Loaded plugins: fastestmirror L ...
- gerrit 使用笔记
添加git hooks git库的钩子目录中有一个commit-msg脚本文件,可以在git执行commit时,在提交信息中自动添加一个唯一的Change-Id scp -P 29419 admin@ ...
- C++学习22 多态的概念及前提条件
在<C++基类和派生类的赋值>一节中讲到,基类的指针也可以指向派生类对象.请看下面的例子: #include <iostream> using namespace std; c ...
- [ActionScript 3.0] AS3 实现XML转换成JSON
package com.fylib.util { /** * @author Frost.Yen * @E-mail 871979853@qq.com * @create 2015-6-18 下午2: ...
- 前后台彻底分离的核心文件bridge.js.
具体代码可以在我的git上下载:https://github.com/guoyansi/bridge 这里的后台使用java写的,如果不了解java的童鞋可以忽略下面这样图片. bridge.js / ...
- MongoDB 多条件组合查询
组合条件查询json格式语法 { "$and": [ { "Date": { $gt: ISODate("2015-06-05T00:45:00.00 ...
- uWSGI其三:uWSGI搭配Nginx使用
http://www.nowamagic.net/academy/detail/1330334 上一篇介绍了 uWSGI 来部署 Django 程序,但在在生产环境中单单只有 uWSGI 是不够的,N ...
- esriSRGeoCS2Type Constants
ArcGIS Developer Help (Geometry) esriSRGeoCS2Type Constants More geographic coordinate systems. ...