查找和排序的基本操作:查找排序算法大集合

重点

查找算法着重掌握:顺序查找、二分查找、哈希表查找、二叉排序树查找。

排序算法着重掌握:冒泡排序、插入排序、归并排序、快速排序。

顺序查找

算法说明

顺序查找适合于存储结构为顺序存储或链接存储的线性表。

算法思想

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

算法实现

int sequenceSearch(int a[], int value, int len)
{
    int i;
    for(i=0; i<len; i++)
        if(a[i]==value)
            return i;
    return -1;
}

算法分析

查找成功时的平均查找长度为:(假设每个数据元素的概率相等) ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;查找不成功时,需要n+1次比较,时间复杂度为O(n);所以,顺序查找的时间复杂度为O(n)


二分查找

算法说明

元素必须是有序的,如果是无序的则要先进行排序操作。

算法思想

也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。注:折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。

算法实现

//二分查找,常规版
int binarySearch1(int a[], int value, int len)
{
    int low, high, mid;
    low = 0;
    high = len-1;
    while(low<=high)
    {
        mid = low+(high-low)/2;    //防止溢出
        if(a[mid]==value)
            return mid;
        if(a[mid]>value)
            high = mid-1;
        if(a[mid]<value)
            low = mid+1;
    }
    return -1;
}

//二分查找,递归版
int binarySearch2(int a[], int value, int low, int high)
{
    int mid = low+(high-low)/2;
    if(a[mid]==value)
        return mid;
    if(a[mid]>value)
        return BinarySearch2(a, value, low, mid-1);
    if(a[mid]<value)
        return BinarySearch2(a, value, mid+1, high);
}

算法分析

最坏情况下,关键词比较次数为log2(n+1),故时间复杂度为O(log2n);


冒泡排序

算法说明

属于交换类排序,稳定排序

算法思想

比较相邻的两个数的大小,将最大的数放在右边,计数器i++;

继续重复操作1,直到a[n-2]和a[n-1]比较结束,数组a中最大的值已在a[n-1];

将进行排序的数组长度n减1,重复操作1和操作2,直到n为1,排序完毕。

算法实现

void bubbleSort(int* array, int length)
{
    for (int i = 0; i < length - 1; ++i)
    {
        //bool is_Swap=false;
        for (int j = 0; j < length - 1 - i; ++j)
        {
            if (array[j] > array[j + 1])
            {
                //is_Swap=true;
                int temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
                /*
                交换还可使用如下方式
                a = a + b;
                b = a - b;
                a = a - b;
                交换还可使用如下方式
                a=a^b;
                b=b^a;
                a=a^b;
                */
            }
        }
        //if(is_Swap==false)
            //return;
    }
}

算法分析

平均时间复杂度:O(n^2)。最好的情况:如果待排序数据序列为正序,则一趟冒泡就可完成排序,排序的比较次数为n-1次,且没有移动,时间复杂度为O(n)。要实现O(n)的复杂度,代码里需要加一个标志位(Bool变量)。最坏的情况:如果待排序数据序列为逆序,则冒泡排序需要n-1次趟,每趟进行n-i次排序的比较和移动,即比较和移动次数均达到最大值:比较次数=n(n−1)/2=O(n^2),移动次数等于比较次数,因此最坏时间复杂度为O(n^2)。


插入排序

算法说明

属于插入类排序,稳定排序。

算法思想

从待排序的数组的第二个元素开始,将其与前面的数进行大小比较,寻找合适的位置并插入,直到全部元素都已插入。

算法实现

void insertSort(int* array,int length)
{
    int i = 0, j = 0, temp = 0;
    for (i = 1; i < length; ++i)
    {
        //如果该元素小于前面的元素,大于该元素的元素全部后移一位,
        //直到找到该元素要插入的位置并插入之。
        if (array[i] < array[i-1])
        {
            temp = array[i];
            for (j = i-1; temp < array[j] && j >= 0 ; --j)
            {
                array[j+1] = array[j];
            }
            array[j + 1] = temp;
        }
    }
}

算法分析

 平均时间复杂度:O(n^2)。最好的情况:当待排序记录已经有序,这时需要比较的次数为n-1=O(n)。最坏的情况:如果待排序记录为逆序,则最多的比较次数为n*(n-1)/2=O(n^2)


归并排序

算法说明

应用较广,稳定排序。

算法思想

归并排序是分治法的一个典型的应用,先使每个子序列有序,再使每个子序列间有序。将两个有序子序列合并成一个有序表,称为二路归并。 步骤:首先将有序数列一分二,二分四……直到每个区都只有一个数据,此时每个子序列都可看做有序序列。然后进行合并,每次合并都是有序序列在合并,

算法实现

void MergeArray(int* array, int first, int mid, int last, int* temp)
{
    //将a[first...mid]和a[mid+1...last]合并
    int i = first, j = mid + 1, k = 0;
    int lengthA = mid+1, lengthB = last+1;
    while (i < lengthA&&j < lengthB)
    {
        if (array[i] < array[j])
            temp[k++] = array[i++];
        else
            temp[k++] = array[j++];
    }
    while (i < lengthA)
    {
        temp[k++] = array[i++];
    }
    while (j < lengthB)
    {
        temp[k++] = array[j++];
    }
    for (i = 0; i < k; ++i)
    {
        array[first + i] = temp[i];
    }
}

void MergeSort(int* array, int first, int last, int* temp)
{
    if (first >= last)
        return;
    int mid = (first + last) / 2;
    MergeSort(array, first, mid, temp);//左边有序
    MergeSort(array, mid + 1, last, temp);//右边有序
    MergeArray(array, first, mid, last, temp);//合并两个有序的子序列
}

算法分析

平均、最好、最坏的时间复杂度都为:O(n*log n)

可以这样理解:合并需要O(log n)步操作,每步将排好序的子序列合并需要O(n)的操作。那时间复杂度肯定是O(n*log n)。


快速排序

算法说明

在交换类排序算法中,快排是速度最快的。采用分治的思想,不稳定排序。

算法思想

从n个元素中选择一个元素作为分区的标准,一般选第一个元素;

把小于该元素的放在左边,把大于等于该元素的放在右边,中间就放该元素;

再分别对左右子序列重复操作1和2,直到每个子序列里只有一个元素,排序完毕。

算法实现

//版本1
void QuickSort(int* array,int low,int high)
{
    if (low >= high)
        return;
    int left = low;
    int right = high;
    int key = array[left];//选择第一个元素作为区分元素,当然也可以选最后一个元素。
    while (left != right)
    {
        while (left != right&&array[right] >= key)//从右往左,把小于key的元素放到key的左边
            --right;
        array[left] = array[right];
        while (left != right&&array[left] <= key)//从左往右,把大于key的元素放到key的右边
            ++left;
        array[right] = array[left];
    }
    array[left] = key;//此时left等于right

    //一分为二,分治思想,递归调用。
    QuickSort(array, low, left - 1);
    QuickSort(array, left + 1, high);
}

众所周知,Partition函数不管是在快速排序中,还是在找第K大这类问题中,都有很重要的地位,故而分开写,就有了版本2。

int Partition(int* array,int left,int right)
{
    int key = array[left];
    while (left != right)
    {
        while (left != right&&array[right] >= key)//从右往左,把小于key的元素放到key的左边
            --right;
        array[left] = array[right];
        while (left != right&&array[left] <= key)//从左往右,把大于key的元素放到key的右边
            ++left;
        array[right] = array[left];
    }
    array[left] = key;
    return left;//返回区分函数
}

//快排主函数
void quicksort(int* arr, int left, int right)
{
    if(left< right)
    {
        int middle = mypartition(arr, left, right);
        quicksort(arr, left, middle-1);
        quicksort(arr, middle+1, right);
    }
}

算法分析

平均时间复杂度:O(n*log n)。原因:快排是将数组一分为二到底,所以需要O(log n)次此操作,每次操作需要排序n次,所以,大多数情况下,时间复杂度都是O(n*log n)。最好的情况:是每趟排序结束后,每次划分使两个子文件的长度大致相等,时间复杂度为O(n*log n)。最坏的情况:是待排序元素已经排好序。第一趟经过n-1次比较后第一个元素保持位置不变,并得到一个n-1个元素的子序列;第二趟经过n-2次比较,将第二个元素定位在原来的位置上,并得到一个包括n-2个元素的子序列,依次类推,这样总的比较次数是:n(n-1)/2=O(n^2)。



查找和排序的基本操作:查找排序算法大集合

原文地址:https://www.cnblogs.com/parzulpan/p/11258491.html

时间: 2024-12-16 11:44:51

查找和排序的基本操作:查找排序算法大集合的相关文章

算法大神之路----排序(选择排序法)

选择排序法,顾名思义,就是把特定的数据选择出来进行排序. 选择排序法有两种方式 在所有的数据中,当由大到小排序,那么就将最大值放到第一个位置 如果由小到大排序,那么就将最小值放到第一个位置 以由小到大排序举例,当排序时候,扫描整个数据,拿第一个依次与其他做比较,如果其他数据比第一个大,或者相等,那么就不交换,如果其他数据比第一个数小,那么就交换二者的位置,扫描结束后,则从第二个数开始,依次扫描. 方法分析 无论是最坏还是最好情况,甚至是平均情况下,都需要对全部数据进行扫描,找到最大或最小值,因此

Java学习 (七)、数组,查找算法,二分查找法,冒泡排序,选择排序,插入排序

一.常用数组查找算法 工作原理:它又称为顺序查找,在一列给定的值中进行搜索,从一端的开始逐一检查每个元素,知道找到所需元素的过程. 例1:查找指定的数在数组中出现的位置,找到返回下标,找不到返回-1 1 import java.util.Scanner; 2 public class LinearSearch{ 3 public static void main(String []argas) 4 { 5 int [] array={10,100,90,65,80,92}; 6 System.o

查找与排序01,线性查找,时间复杂度,算法

线性查找,肯定是以线性的方式,在集合或数组中查找某个元素.本篇包括: 通过代码来理解线性查找 时间复杂度 什么是算法 通过代码来理解线性查找 什么叫"线性"?还是在代码中体会吧. 首先需要一个集合或数组,如何得到呢?就生成一个固定长度的随机数组吧.然后输入一个查找key,如果找到就返回元素的索引,没找到就返回-1,就这么简单. class Program { private static int[] arr; private static Random r = new Random()

查找与排序02,折半查找

折半查找,也叫二分查找,当在一个数组或集合中查找某个元素时,先定位出中间位置元素,如果要查找的元素正好和该中间位置元素相等,通过一次查找,就能找到匹配元素:如果要查找的元素小于该中间位置元素,就抛弃后面一半的元素,在前面一半的元素中再定位出中间位置元素,如此反复,直到找到匹配元素:如果要查找的元素大于该中间位置元素,就抛弃前面一半的元素,在后面一半的元素中定位出中间位置元素,如此反复. 面临的第一个问题是:中间位置元素如何定位?在折半查找中规定:当元素个数是奇数,比如有3个元素,中间位置元素是索

基础排序、二分查找汇总

一.常见排序算法复杂度和稳定性 二.js代码实现和思路 (1)冒泡排序:从数组起始位置两两比较,前一个大于后一个就交换位置,第一轮比较后最大的那个数就排到了最后,循环比较数组长度-1次 function bubble (arr) { for (let j = 0; j < arr.length - 1; j++) { for (let i = 0; i < arr.length - 1 - j; i++) { if (arr[i] > arr[i + 1]) { [arr[i], arr

在排序数组中查找元素

/* 34.在排序数组中查找元素的第一个和最后一个位置. 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [-1, -1]. */ #include<stdio.h> #include<malloc.h> #include<string.h> #include<stdlib.h> #include<mat

【LeetCode】34. 在排序数组中查找元素的第一个和最后一个位置

题目 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是?O(log n) 级别. 如果数组中不存在目标值,返回?[-1, -1]. 示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 示例?2: 输入: nums = [5,7,7,8,8,10], target = 6 输出: [-1,-1] 本题同[剑指Offer]面试题53 - I. 在排序数组

4种基本排序&2种查找

<?php $arr=array(5,2,1,7,8,6,3,10,9); showArray($arr); /** * 遍历打印数组 * @param string $type  排序方式 * @param array $arr    排序数组 */ function showArray($arr,$type='原数组'){ echo "$type:<br/>"; foreach ($arr as $v){ echo ' '.$v.' '; } echo '<

hdu 4938 Seeing People 排序+二分查找

Seeing People Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 241    Accepted Submission(s): 61 Problem Description There are two kinds of people. If person i is the first kind of people, it