查找和排序算法

[TOC]

二分查找算法

int Search_Bin(int *a,int val,int n)
{//成功返回算法数组中指定值的位置,如果失败了,就返回error;前提是数组时有序的,没序gg
    int low = 0;
    int high = n-1;
    while(low<=high)
    {
        mid =(low+high)/2;
        if(a[mid]==val) return mid;
        else if(val > a[mid]) low = mid+1;
        else high = mid-1;
    }//如果跳出了循环意味着,查找失败了.
    return error;
}

递归调用形式

int Search_Bin(int *a,int val,int begin,int end)
{
    int mid = (begin+end)/2;
    if(a[mid]==val)
      return mid;
    else if(val>a[mid])
      return Serach_Bin(a,val,mid+1,end);
    else return Search_Bin(a,val,begin,mid-1);
    
}

插入排序

算法步骤:

1)将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

2)从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

void insert_sort(int *a,int n)
{
  int i,j;
  int temp;
  for(i=1;i0&&a[j-1]>temp;j--)//a[j-1]>temp意味着前面的大就往后移动,然后小的插在前面.
    {
      a[j] = a[j-1];//记录往后移
    }
    a[j] = temp;//插入合适的位置
  }
}

希尔排序

希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

头大,插入排序的改进版,增量缩小的插入排序

void shellInsert(int array[],int n,int dk)
{
    int i,j,temp;
    for(i = dk;i < n;i++)//分别向每组的有序区域插入
    {
        temp = array[i];
        for(j = i-dk;(j >= i % dk) && array[j] > temp;j -= dk)//比较与记录后移同时进行
            array[j + dk] = array[j];
        if(j != i - dk)
            array[j + dk] = temp;//插入
    }
}
 
//计算Hibbard增量,当这样设置增量的时候效率是最高的.
int dkHibbard(int t,int k)
{
    return int(pow(2,t - k + 1) - 1);
}
 
//希尔排序
void shellSort(int array[],int n,int t)
{
    void shellInsert(int array[],int n,int dk);
    int i;
    for(i = 1;i <= t;i++)
        shellInsert(array,n,dkHibbard(t,i));
}
 

并不好理解,代码看得不是很懂...

选择排序

算法步骤

1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

2)再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

3)重复第二步,直到所有元素均排序完毕。

void select_sort(int *a,int n)
{
  int i,j,min,t;
  for(i=0;ia[j])
        min = j; //需要交换了
    if(min!=i)
    {
      t = a[min];
      a[min]=a[i];
      a[i] = t;
    }
  }
}

堆排序

维护堆:

MAX-HEAPIFY(A,i)
  l=LEFT(i)
  r = RIGHT(i)
  if l <= A.heap-size and A[l]>A[i]
      largest = l
  else largest = i
  if r <= A.heap-size and A[r]>A[i]
      largest = r
  if largest <> i
      exchange A[i] with A[largest]
      MAX-HEAPIFY(A,largest)

唯一难理解就是递归结束条件:当是叶子节点或者已经是最大堆的时候就可以结束了.这个维护堆的过程只是比较了,当前节点和他子节点的大小,然后进行维护的

建堆:

BUILD-MAX-HEAP(A)
  A.heap-size = A.length
  for i = [A.length/2] downto 1
      MAX-HEAPIFY(A,i)

明显A.length/2到n的都是叶子节点,因此不用维护.

堆排序算法:

HEAPSORT(A)
  BUILD-MAX-HEAP(A)
  for i = A.length downto 2
      exchange A[1] with A[i]
      A.heap_size = A.heap_size - 1 
      MAX-HEAPIFY(A,1)
#include 
using namespace std;
#define maxn 101;
int heap_size = 0;
int length = 0;
// 维护堆的过程
void maxHeapfity(int A[],int i)
{
    printf("maxHeapfity(A,%d)\n",i);
    for(int i = 1;i<=heap_size;i++)
        cout << A[i]<< " ";
    cout << endl;
    int left = 2*i;
    int right = 2*i+1;
    int largest = i;
    if(left <= heap_size && A[left]>A[i])
        largest = left;
    if(right <= heap_size && A[right]>A[largest])
        largest = right;
    if(largest != i){
        printf("exchange %d with %d\n",A[i],A[largest]);
        int temp = A[i];
        A[i] = A[largest];
        A[largest] = temp;
        maxHeapfity(A,largest);
    }
}
//建堆的过程
void buildMaxHeap(int *A)
{
    heap_size = length;
    for(int i = length/2;i>=1;i--)
        maxHeapfity(A,i);
}

//排序算法

void heapSort(int *A)
{
    buildMaxHeap(A);
    for(int i = length;i>=2;i--){
        printf("the max is %d\n",A[1]);
        int temp = A[1];
        A[1] = A[i];
        A[i] = temp;
        heap_size -= 1;
        maxHeapfity(A,1);
    }
}
int main() {
    int A[] = {0,16,14,10,8,7,9,3,2,4,1};
    length = 10;
    heapSort(A);
    for(int i =1;i<=length;i++){
        printf("%d ",A[i]);
    }
    return 0;
}

冒泡排序

算法步骤

1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

3)针对所有的元素重复以上的步骤,除了最后一个。

4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

void bubble_sort(int *a,int n)
{
  int i,j,temp;
  for(i=0;ia[j+1]) // 如果前面的大就把它提取出来,从小到大的排序
        {
          temp = a[j];
          a[j]=a[j+1];
          a[j+1] = temp;
        }
}

快速排序

算法步骤:

1 从数列中挑出一个元素,称为 “基准”(pivot),

2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

void Qsort(int *a,int low,int high)
{
  if(low>=high)
    return;
  int first = low;
  int last  = high;
  int key = a[first];//用字表的第一个记录作为轴
  while(first=key)
      --last;
    a[first] = a[last];//将比第一个小的移到低端
    while(first

这个代码很简短,可以,很好.

归并排序

算法步骤:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

  4. 重复步骤3直到某一指针达到序列尾

  5. 将另一序列剩下的所有元素直接复制到合并序列尾

void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = startIndex;
    while(i != midIndex + 1 && j != endIndex + 1)
    {
        if(sourceArr[i] >= sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];
    for(i = startIndex; i <= endIndex; i++)
        sourceArr[i] = tempArr[i];
}
 
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = (startIndex + endIndex) / 2;
        MergeSort(sourceArr, tempArr, startIndex, midIndex);
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}

基数排序

int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
    int d = 1; //保存最大的位数
    int p = 10;
    for(int i = 0; i < n; ++i)
    {
        while(data[i] >= p)
        {
            p *= 10;
            ++d;
        }
    }
    return d;
}
void radixsort(int data[], int n) //基数排序
{
    int d = maxbit(data, n);
    int *tmp = newint[n];
    int *count = newint[10]; //计数器
    int i, j, k;
    int radix = 1;
    for(i = 1; i <= d; i++) //进行d次排序
    {
        for(j = 0; j < 10; j++)
            count[j] = 0; //每次分配前清空计数器
        for(j = 0; j < n; j++)
        {
            k = (data[j] / radix) % 10; //统计每个桶中的记录数
            count[k]++;
        }
        for(j = 1; j < 10; j++)
            count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
        for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
        {
            k = (data[j] / radix) % 10;
            tmp[count[k] - 1] = data[j];
            count[k]--;
        }
        for(j = 0; j < n; j++) //将临时数组的内容复制到data中
            data[j] = tmp[j];
        radix = radix * 10;
    }
    delete[]tmp;
    delete[]count;
}

总结

image.png

参考: https://www.cnblogs.com/RainyBear/p/5258483.html

你可能感兴趣的:(查找和排序算法)