算法之查找与排序

一、查找

1.线性表的查找

1.1 顺序查找

1.2 折半查找

1.3 分块查找

2.树表的查找

2.1 二叉排序树

2.2平衡二叉树

LL

RR

LR

RL

红黑树

B-树

B+树

键树

3.哈希表的查找

构造散列函数考虑的因素:

  执行速度

  关键字的长度

  散列表的大小

  关键字的分布情况

  查找频率

3.1 直接定值法

3.2 数字分析法

3.3 平方取中法

3.4 折叠法

3.5 除留余数法

3.6 随机数法

处理冲突的方法

3.1 开放地址法

  线性探测、二次探测、伪随机探测

3.2 链地址法

3.3 再散列法

3.4 建立一个公共溢出区

二、排序

1. 插入排序

有序插入

1.1 直接插入排序

x = a[i];
for (int j = 0; j>=0 && x<a[j]; j--)
{
	a[j+1] = a[j];
}
a[j-1]=x;

使用哨兵

void InsertSort(SqList &L){
	int i,j;
	for(i=2;i<=L.length;i++){
		if(L.r[i].key < L.r[i-1].key){
			L.r[0] = L.r[i];
			for(j=i-1;L.r[0].key<L.r[j].key;j--){
				L.r[j+1] = L.r[j];
			}
			L.r[j+1] = L.r[0];
		}
	}
}

  时间复杂度n*n

  空间复杂度1

  稳定

#include<stdio.h>

int main()
{
    int nums[100001];
    int n,i,j,x;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&nums[i]);
    for(i=1;i<n;i++)
    {
        x = nums[i];
        for(j=i-1;j>=0&&x<nums[j];j--)
        {
            nums[j+1] = nums[j];
        }
        nums[j+1] = x;
    }
    for(i=0;i<n;i++)
        printf("%d ",nums[i]);
    return 0;
}

1.2 折半插入排序

1.3 希尔排序

  时间复杂度 n的7/6次方

  空间复杂度1

  不稳定

2. 交换排序

2.1 冒泡排序

#include<stdio.h>

int main()
{
    int nums[100001];
    int n,i,j,x;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&nums[i]);
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-i-1;j++)
        {
            if(nums[j]>nums[j+1])
            {
                x = nums[j+1];
                nums[j+1] = nums[j];
                nums[j]=x;
            }
        }
    }
    for(i=0;i<n;i++)
        printf("%d ",nums[i]);
    return 0;
}

  时间复杂度n*n

2.2 快速排序

任选一个元素为中心,比它小的放左边,比它大的放右边,形成左右两个子表

对每个子表重新选择中心元素并依此规则调整

直到每个子表的元素只剩一个

#include<stdio.h>

int Partition(int nums[],int low,int high)
{
    nums[0] = nums[low];
    int key = nums[low];
    while(low<high){
        while(low<high && nums[high]>=key) high--;
        nums[low] = nums[high];
        while(low<high && nums[low]<=key) low++;
        nums[high] = nums[low];
    }
    nums[low] = nums[0];
    return low;
}

void QSort(int nums[],int low,int high)
{
    int newlen;
    if(low<high){
        newlen = Partition(nums,low,high);
        QSort(nums,low,newlen-1);
        QSort(nums,newlen+1,high);
    }
}

int main()
{
    int nums[100001];
    int n,i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&nums[i]);
    QSort(nums,1,n);
    for(i=1;i<=n;i++)
        printf("%d ",nums[i]);
    return 0;
}

  时间复杂度n*logn

  不稳定

 

#include <iostream>

int a[5000005],k;

using namespace std;

int quicksort(int left,int right)
{
	int mid=a[left];
	while (left<right)
	{
		while (left<right&&mid<=a[right])
			right--;
		a[left] = a[right];
		while (left<right&&a[left]<=mid)
			left++;
		a[right] = a[left];
	}
	a[left]=mid;
	return left;
}
int find(int left, int right, int k)
{
	int tem=quicksort(left,right);
	if(k==tem)
		printf("%d",a[k]);
	else if(k-1<tem)
		find(left,tem-1,k);
	else
		find(tem+1,right,k);
	return 0;
}

int main()
{
    int n;
    scanf("%d %d",&n,&k);

    //a = new int [n];
    for(int i=0;i<n;++i)
        scanf("%d",&a[i]);
    find(0,n-1,k);
    //delete [] a;
    return 0;
}

 

  

 

3. 选择排序

3.1 简单选择排序

#include<stdio.h>

int main()
{
    int nums[100010];
    int n,i,k,j,x;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&nums[i]);
    for(i=0;i<n;i++)
    {
        k=i;
        for(j=i+1;j<n;j++)
        {
            if(nums[j] <nums[k]) k=j;
        }
        if(k!=i){
            x = nums[k];
            nums[k] = nums[i];
            nums[i] = x;
        }
    }
    for(i=0;i<n;i++)
        printf("%d ",nums[i]);
}

3.2 堆排序

#include <stdio.h>
#include <stdlib.h>

#define MAXITEM 100


void printArray(int arr[], int n) {
	int i;
	for (i = 1; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}


/*
	生成大根堆
	R:待排序数组
	v:下标
	n:最后一个下标
*/
void Heapify(int R[MAXITEM], int v, int n) {
	int i, j;
	i = v;
	j = i * 2;	// R[i]的左子节点

	R[0] = R[i]; // 暂存父节点的值,方便最终替换时赋值

	while (j <= n) {
		// 先判断左右子节点的大小,再与父节点进行比较
		// 其中 j<n 说明他存在兄弟节点
		if (j<n && R[j]<R[j+1])
		{
			j++; // 右节点比当左子节点大,则用右节点与父节点比较
		}
		// 如果父节点的值小于子节点值
		if (R[i] < R[j]) {
			R[i] = R[j]; // 替换父节点的值
			i = j; // 将要比较的父节点变成当前子节点
			j = 2 * i;	// 将要比较的子节点变成当前子节点的子节点
		}
		else { // 如果父节点不小于则直接退出循环,因为根堆是从下往上构建的,如果父节点不需要替换,子节点自然不用再重新替换
			j = n + 1;
		}
		R[i] = R[0]; // 将父节点的值赋值到当前节点
	}

}
/*
	堆排序算法
	本算法舍弃了数组下标0的空间,直接从下标1开始排序
*/
void HeapSort(int R[MAXITEM], int n) {
	int i;
	// 将数组先变成一个大根堆
	// n/2 一定是最后一个非叶子节点,其前面的都是非叶子节点
	for (i = n / 2; i >= 1; i--) {
		Heapify(R, i, n);
	}
	// 大根堆只需要保证其父节点的值大于左右子节点的值即可,无需排列的很整齐
	//printf("初始构建大根堆:");
	//printArray(R, n + 1);
	// 开始排序,将根节点移除在外,然后用最后一个叶子节点代替根节点
	for (i = n; i > 1; i--)
	{
		// 将根节点与最后一个叶子节点交换位置,R[0]作为临时空间存在,用于存放要交换的数据
		R[0] = R[i];
		R[i] = R[1];
		R[1] = R[0];
		// 将最后一个数(也就是根节点)排除在外后再进行构建堆操作
		Heapify(R, 1, i - 1);
		//printf("第%d次排序:",n-i+1);
		//printArray(R, n + 1);
	}
}

int main() {
	int arr[100010];
	int n,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
        scanf("%d",&arr[i]);
	// 这里我舍弃了下标0的空间,从下标1开始排序
	HeapSort(arr, n);
	//printf("最终结果:");
	printArray(arr, n+1);
}

  数据结构——堆排序(C语言)_櫆溟的博客-CSDN博客

时间复杂度 n*logn

不稳定

4. 归并排序

#include <iostream>
#include <algorithm>

using namespace std;

void Merge(long long int *a,long long int low,long long int mid,long long int high)
{
    long long int *b = new long long int [high-low+1];
    long long int i=low,j=mid+1,k=0;
    while(i<=mid && j<=high)
    {
        if(a[i]<=a[j])
        {
            b[k++]=a[i++];
        }else
        {
            b[k++]=a[j++];
        }
    }
    while(i<=mid)
    {
        b[k++]=a[i++];
    }
    while(j<=high)
    {
        b[k++]=a[j++];
    }
    k=0;
    for(long long int i=low;i<=high;++i)
    {
        a[i]=b[k++];
    }
    delete []b;
}

void mergesort(long long int *a,long long int low,long long int high)
{
    if(low<high)
    {
        long long int mid = (low+high)/2;
        mergesort(a,low,mid);
        mergesort(a,mid+1,high);
        Merge(a,low,mid,high);
    }
}

int main()
{
    long long int *arr;
    long long int n,k;
    cin>>n>>k;
    arr = new long long int [n];
    for(long long int i=0;i<n;++i)
    {
        cin>>arr[i];
    }
    mergesort(arr,0,n-1);
    cout<<arr[k];
    delete [] arr;
}

  

4.1 2-路归并排序

  时间复杂度 n*logn

  空间复杂度n

  稳定

5. 基数排序(桶排序)

时间复杂度n

6. 外部排序

 

 

posted @ 2022-11-17 20:14  kangobs  阅读(15)  评论(0编辑  收藏  举报