C/C++程序员面试宝典(四)

排序
1、冒泡排序
a.先把你要排的数输入到数组里
b.进行n-1次冒泡排序,从左往右两两比较
c.如果这个数比前面的大,那么就交换
d.依次输出数组

#include <iostream>
using namespace std;
int a[100];
int main()
{
    int n;
    cin >> n;
    for (int i = 0;i < n;i++){
        cin >> a[i]; //输入数组a  
    }
    for (int i = 0;i < n-1;i++){ //如果有n个数,就要连续排序n-1次,每一轮swap后最大数移到数组最右侧
        for (int j = 0;j < n-1-i;j++){ //执行每一次比较的次数,注意这里的j的范围,每次都少比较一次
            if (a[j] > a[j+1]){ //如果这个数比前面的大
                swap(a[j],a[j+1]);//把a[j]和a[j+1]进行交换
            }
        }
    }
    for (int i = 0;i < n;i ++){ //数组输出
        cout << a[i] << ",";
    }
    cout << endl;
    return 0;
}

2、鸡尾酒排序(改进的冒泡排序)
大数往右放,小数往左放,相当于往两边排序,一直进行下去,直至最中间的数。
例如:{3,7,1,5,2}序列:
第一次:{3,1,5,2,7};
第二次:{1,3,5,2,7};
第三次:{1,3,2,5,7};
第四次:{1,2,3,5,7};

#include<iostream>
using namespace std;

void ShowArr(int arr[], int length);
void CocktailSort(int arr[], int length);
void Swap(int arr[], int i, int j);

int main()
{
    int arr[] = { 9,2,3,3,9,7,5,1,9,2,10 };
    int length = sizeof(arr) / sizeof(int);
    CocktailSort(arr, length);
    ShowArr(arr, length);

    return 0;
}

void ShowArr(int arr[], int length)
{
    for (int i = 0; i < length; i++){
        cout << arr[i] << "\t";
    }
    cout << endl;
}

void CocktailSort(int arr[], int length)
{
    if (arr == nullptr || length <= 0)
        return;
    int left = 0;
    int right = length - 1;
    while (left < right) { //循环条件
        for (int i = left; i < right; i++) {
            if (arr[i] > arr[i + 1])
                Swap(arr, i, i + 1); //将最大的移到最右边
        }
        right--; //最右边不用比较
        for (int j = right; j > left; j--) {
            if (arr[j-1] > arr[j])
                Swap(arr, j-1, j); //将最最小的移到最左边
        }
        left++; //最左边的不用比较
    }
}

void Swap(int arr[], int i, int j)
{
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

3、选择排序
从需要排序的队列数据中选择最小的同第一个值交换,再从剩下的部分选择最小的与第二个交换,循环执行下去,最后实现全队列按序的排列。

#include<iostream>
#include<string>
using namespace std;

template <typename T>
void selectionSort(T arr[],int n){
    for(int i=0;i<n;i++){
        //寻找[i,n)区间里的最小值
        int minIndex=i; //为最小值的位置做个标记
        for(int j=i+1;j<n;j++)
            if(arr[j]<arr[minIndex])
                minIndex=j;
        swap(arr[i],arr[minIndex]); //交换最小值和第i个元素
    }
}

int main(){
    int array[10]={10,9,8,7,6,5,4,3,2,1};
    selectionSort(array,10);
    for(int i=0;i<10;i++)
        cout<<array[i]<<" ";

    return 0;
}

4、插入排序
将数组第一个元素认为是有序数组,然后比较第二个元素的关键字与第一个元素关键字的大小,有序排列。将数组后面一个元素的关键字依次插入到前面的有序数组中,一直重复至排序完成。

#include<iostream>
using namespace std;
 
//交换数组元素位置位置
void swap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
/*
插入排序。注意,若后面一个元素比其前面一个元素小,则将这两个元素交换位置,然后再来比较这个插入元素与前面一个元素的大小,若还小,
则还需要交换这两个元素位置,一直到这个插入元素在正确的位置为止
*/
void insertSort(int a[],  int length)
{
	for (int i=1; i < length; i++){
		for (int j = i-1; j >= 0 && a[j+1] < a[j]; j--){ //依次比较
			swap(a[j], a[j+1]); 
		}
	}
}
 
int main()
{
	int a[] = { 2,1,4,5,3,8,7,9,0,6 };
	insertSort(a, 10);
	for (int i = 0; i < 10; i++){
		cout << a[i] << "";
	}

	return 0;
}

5、归并排序
利用归并的思想实现的排序方法,该算法采用经典的分治策略将问题分成一些小的问题然后递归求解,即分而治之。
在这里插入图片描述

#include<iostream>
using namespace std;
 
void Merge(int arr[],int low,int mid,int high){
    //low为第1有序区的第1个元素,i指向第1个元素, mid为第1有序区的最后1个元素
    int i=low,j=mid+1,k=0; //mid+1为第2有序区第1个元素,j指向第1个元素
    int *temp=new int[high-low+1]; //temp数组暂存合并的有序序列
    if(!temp){ //内存分配失败
        cout<<"error";
        return;
    }
    while(i<=mid&&j<=high){
        if(arr[i]<=arr[j]) //较小的先存入temp中
            temp[k++]=arr[i++];
        else
            temp[k++]=arr[j++];
    }
    while(i<=mid)//若比较完之后,第一个有序区仍有剩余,则直接复制到t数组中
        temp[k++]=arr[i++];
    while(j<=high)//同上
        temp[k++]=arr[j++];
    for(i=low,k=0;i<=high;i++,k++)//将排好序的存回arr中low到high这区间
		arr[i]=temp[k];
    delete []temp;//删除指针,由于指向的是数组,必须用delete []
}

//用递归应用二路归并函数实现排序——分治法
void MergeSort(int arr[],int low,int high){
    if(low<high){
        int mid=(low+high)/2;
        MergeSort(arr,low,mid); //这里的递归就是为了将大的数组分成左右两个数组(分),若只是合并两个数组,可以去掉这部分即可
        MergeSort(arr,mid+1,high);
        Merge(arr,low,mid,high); //对分成的左右数组进行元素大小比较并合并(治)
    }
}

int main(){
    int a[10]={5,1,9,3,7,4,8,6,2,0};
    MergeSort(a,0,9);
    for(int i=0;i<10;i++)
        cout<<a[i]<<" ";
    return 0;
}

6、快速排序
a.从数列中取出一个数作为基准数。 (一遍选数组的第一个数)
b.将数组进行划分(partition),将比基准数大的元素都移至枢轴右边,将小于等于基准数的元素都移至枢轴左边。
c.再对左右的子区间重复第二步的划分操作,直至每个子区间只有一个元素。

void QuickSort(int array[], int start, int last)
{
    int i = start;
    int j = last;
    int temp = array[i]; //基准数
    if (i < j){
        while (i < j){
            while (i < j &&  array[j]>=temp ) //从右往左,直到找到比temp小的,进行交换
                j--;
            if (i < j){
                array[i] = array[j];
                i++;
            }

            while (i < j && temp > array[i]) //从左往右,直到找到比temp大的,进行交换
                i++;
            if (i < j){
                array[j] = array[i];
                j--;
            }           
        }
        //把基准数放到i位置
        array[i] = temp;
        //分别对左右继续进行递归实现快速排序
        QuickSort(array, start, i-1);
        QuickSort(array, i+1, last);
    }
}

7、希尔排序(插入排序的一种)
a.先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中,在各组内进行直接插人排序。
b.取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
步长的选择是希尔排序的重要部分。只要最终步长为1任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
在这里插入图片描述

//交换数组元素
void swap(int *a,int i,int j)
{
    int t = a[i];
    a[i] = a[j];
    a[j] = t;
}
//希尔排序
void shell_sort(int *a,int len)
{
    int h=1,i,j;
    while(h<len/3){  //寻找合适的间隔h
        h = 3*h+1;
    }
    while(h>=1){
        //将数组变为间隔h个元素有序
        for (i = h; i < len; i++){
            //间隔h插入排序
            for (j = i; j >= h && a[j] < a[j-h]; j -= h){
                swap(a, j, j-h);
            }
        }
        h /= 3;
    }
}

8、堆排序
a.建立大根堆–将n个元素组成的无序序列构建一个大根堆(堆排序的第一步)
在这里插入图片描述
在这里插入图片描述
b.交换堆元素–交换堆尾元素和堆首元素,使堆尾元素为最大元素
在这里插入图片描述
c.重建大根堆–将前n-1个元素组成的无序序列调整为大根堆
在这里插入图片描述
e.重复执行步骤二和步骤三,直到整个序列有序
在这里插入图片描述

#include<iostream>
#include<vector>
using namespace std;
 
//递归方式构建大根堆(len是arr的长度,index是第一个非叶子结点的下标)
void adjust(vector<int> &arr, int len, int index)
{
    int left = 2*index + 1; //index的左子结点
    int right = 2*index + 2; //index的右子结点
 
    int maxIdx = index;
    if(left<len && arr[left] > arr[maxIdx])     maxIdx = left;
    if(right<len && arr[right] > arr[maxIdx])     maxIdx = right;
 
    if(maxIdx != index){
        swap(arr[maxIdx], arr[index]);
        adjust(arr, len, maxIdx);
    }
}
 
// 堆排序
void heapSort(vector<int> &arr, int size)
{
    // 构建大根堆(从最后一个非叶子结点向上)
    for(int i=size/2 - 1; i >= 0; i--){
        adjust(arr, size, i);
    }
 
    // 调整大根堆
    for(int i = size-1; i >= 1; i--){
        swap(arr[0], arr[i]);   // 将当前最大的放置到数组末尾
        adjust(arr, i, 0);   // 将未完成排序的部分继续进行堆排序
    }
}
 
int main()
{
    vector<int> arr = {8, 1, 14, 3, 21, 5, 7, 10};
    heapSort(arr, arr.size());

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值