笔试面试中遇到的最多的问题就是一些排序算法,总结一下数据结构中的一些常见的排序算法,一来做一个梳理,二来方便日后复习。可能需要陆陆续续几天的记录。一点点来。好了废话不多说,进入正题。
1.选择排序(SelectSort)
基本思路:
1.对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换;
2.对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换;
3.重复该过程,直到进行比较的记录只有一个为止;
eg :->
[38 65 97 76 13 27 49]
13 [65 97 76 38 27 49]
13 27 [97 76 38 65 49]
13 27 38 [76 97 65 49]
13 27 38 49 [97 65 76]
13 27 38 49 65 [97 76]
13 27 38 49 65 76 [97]
13 27 38 49 65 76 97
C++程序示例如下
void SelectSort(int *a,int n){
int i,j;
//存储最小的临时数据
int temp = 0;
//标记最小值的下标
int flag = 0;
for (i = 0; i<n-1; i++) {
temp = a[i];
flag = i;
for (j =i+1; j<n; j++) {
if (a[j]<temp) {
temp = a[j];
flag = j;
}
}
if (flag !=i) {
a[flag]= a[i];
a[i] =temp;
}
}
}
2.插入排序(InsertSort)
基本思路:
1.假设第一个记录自成一个有序序列,其余的记录为无序序列;
2.从第二个记录开始,按照记录的大小依次将当前处理的记录插入到其之前的有序序列中;
3.重复上一个步骤处理接下来的记录,直到最后一个记录插入到有序序列中为止;
eg:->
[38 65 97 76 13 27 49]
[38] 65 97 76 13 27 49
[38 65] 97 76 13 27 49
[38 65 97] 76 13 27 49
[38 65 76 97] 13 27 49
[13 38 65 76 97] 27 49
[13 27 38 65 76 97] 49
[13 27 38 49 65 76 97]
C++程序示例如下:
void InsertSort(int *a,int n){
int i,j;
for (i = 0; i<n; i++) {
int temp = a[i];
for ( j = i-1; j>=0; j--) {
if (a[j]>temp) {
a[j+1] = a[j];
}else break;//break出去后j指向第一个小于temp的值
}
a[j+1] = temp;
}
}
3.冒泡排序(BubbleSort)
基本思路:(假设由小到大排序)
1.从第一个记录开始对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换其位置,进行一轮比较换位后,n个记录中的最大记录将位于第n位;
2.对前n-1个记录进行第二轮比较。
3.重复该过程直到比较的记录只剩下一个为止
eg :->
{36 25 48 12 25 65 43 57}
[25 36 12 25 48 43 57] 65
[25 12 25 36 43 48] 57 65
[12 25 25 36 43] 48 57 65
[12 25 25 36] 43 48 57 65
[12 25 25] 36 43 48 57 65
[12 25] 25 36 43 48 57 65
[12] 25 25 36 43 48 57 65
C++程序示例如下:
void BB_Swap(int& a,int& b){
int temp = a;
a= b;
b= temp;
}
void BubbleSort(int *a,int n){
for (int i = 0; i<n-1; i++) {
for (int j =n-1; j>i; --j) {
if (a[j]<a[j-1]) {
BB_Swap(a[j],a[j-1]);
}
}
}
}
4.双向冒泡排序
双向冒泡排序是冒泡拍戏的一种优化,他的基本思想是设置两个指针(left,right),left指向第一个元素,right指向最后一个元素。第一趟(第一次do....while)的时候把最小的冒到最左边,left指针右移一位,然后最大的冒到最右边,right左移一位。依次循环直到left>right。
eg :->
{36 25 48 12 25 65 43 57}
第一趟:[12] 36 25 48 25 43 65 57 [12] 25 36 25 43 48 57 [65]第二趟:[12 25] 25 36 43 48 57 [65] [12 25] 25 36 43 48 [57 65]
第三趟:[12 25 25] 36 43 48 [57 65] [12 25 25] 36 43 [48 57 65]
第四趟:[12 25 25 36] 43 [48 57 65] [12 25 25 36] [43 48 57 65]
C++程序示例如下:
void BB_Swap(int& a,int& b){
int temp = a;
a= b;
b= temp;
}
//双向冒泡排序
void Bubble2Sort(int *a,int n){
int left = 1;
int right = n -1;
int t;
do {
//筛选最小的到左边
for (int i = right; i>left; i--) {
if (a[i]<a[i-1]) {
BB_Swap(a[i], a[i-1]);
t =i;
}
}
left = t+1;//下次循环以及下面的筛选最右边的时候可以忽略左边排好的
//筛选最大的到右边
for (int j =left; j<right+1; j++) {
if (a[j]<a[j-1]) {
BB_Swap(a[j], a[j-1]);
t=j;
}
}
right = t-1;//注意 -1
} while (left<=right);
}
5.归并排序
归并排序是利用递归和分治技术将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列。
其中"归"代表的是递归的意思,即递归的将数组折半地分离为单个数组。eg:[5 4 8 0] => [5 4] [8 0] =>[5] [4] [8] [0].
其中"并"就是就是将分开的数据按照从小到大或者从大到小的顺序再放到一个数组中。eg: <1>[5] [4] =>[4 5] [8] [0] =>[0 8]; <2>[4 5] [0 8] =>[0 4 5 8]
所以归并排序其实就两个步骤:<1>划分子表;<2>合并半子表。
eg:
[49] [38] [65] [97] [76] [13] [27]
[38 49] [65 97] [13 76] [27]
[38 49 65 97] [13 27 76]
[13 27 38 49 65 76 97]
C++程序示例如下:
//归并排序--合并
void Merge(int *a,int p,int q,int r)
{
int i,j,k;//定义在外面是因为循环体外要用到这两个元素
int n1 = q-p+1;//因为吧q剪掉了--
int n2 = r-q;
int *L = new int[n1];
int *R = new int[n2];
for (int i = 0,k = p; i<n1; i++,k++) {
L[i]=a[k];
}
for (int i = 0,k = q+1; i<n2; i++,k++) {//q+1,因为q是左边最后一个元素
R[i]=a[k];
}
for (k = p,i= 0,j=0;i<n1&&j<n2 ;k++ ) {
if (L[i]<R[j]) {
a[k] = L[i];
i++;
}else{
a[k] = R[j];
j++;
}
}
if (i<n1) {
for (j=i; j<n1; j++,k++) {//j=i,因为这时j一定不会小于n2,所以j用不到了
a[k] = L[j];
}
}
if (j<n2) {
for (i=j; i<n2; i++,k++) {
a[k]= R[i];
}
}
}
//归并排序
void MergeSort(int *a,int p,int r)
{
if (p<r) {
int q = (p+r)/2;
//递归左边
MergeSort(a,p,q);
//递归右边
MergeSort(a,q+1,r);
//合并
Merge(a,p,q,r);
}
}
6.快速排序
快速排序的思想是经过一趟排序后将原序列分为两部分,其中左边部分的序列都小于右边部分的序列,其实这里有一个参照数(一般都选序列第一个元素),放置到一个临时变量里用来做比较做比较,两个指针i和j,分别指向第一个元素和最后一个元素。j指针向左扫描,直到遇到第一个小于参照数的元素,这时i指针指向的元素被保存到了临时变量里,所以i指针指向的值变了也没关系,然后就把j指针指向的值放到i指针指向的地址上。然后i向前挪一位。然后i向右扫描,直到遇到第一个大于参照数的值的下标,这时j指向的值在之前j向左扫描的时候被保存了一份,所以j改掉没关系,就把i扫描到的值放入j指向的地址。重复以上两个步骤,直到i>=j的时候。这时候i指针指向的值被保存了一份到j上,所以把参照数放置到i指针指向的地址上。接着对参照数(i指向的值)的左边和右边分别再次重复以上步骤。
C++程序示例如下:
void QuickSort(int array[],int low,int hight)
{
if (low>=hight) {
return;
}
//获得首尾指针副本 因为low和hight在接下去的递归上还要用到,不能变
int i = low,j = hight;
//设置参照数
int index = array[i];
while(i<j)
{
while (i<j&&array[j]>=index)
j--;
//注意while和if
if (i<j) {
array[i++]=array[j];
}
while (i<j&&array[i]<=index)
i++;
if (i<j) {
array[j--] = array[i];
}
}
array[i]= index;
QuickSort(array, low, i);
QuickSort(array, i+1, hight);
}
7:希尔排序
void ShellSort(int array[],int len)
{
for (int h = len/2; h>0; h=h/2) {
for (int i = h; i<len; i++) {
int temp = array[i];
int j;
for (j = i-h; j>=0; j = j-h) {//注意 j>=0 不然第一个不会做排序
if (temp <array[j]) {
array[j+h] = array[j];
}
else
break;//break出去后j指向第一个大于temp的值
}
array[j+h] = temp;
}
}
}