八大排序总结-数据结构

排序算法:

内部排序和外部排序。
1.内部排序是数据记录在内存中进行排序
2.外部排序因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
常见的内部排序:有如下八种。

插入排序:
1.将第一待排序序列的第一个元素看作一个有序序列,把第二个元素到最后一个元素当成未排序序列。
2.从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插到相等元素的后面)

//插入排序
void insert(int ar[],int len)
{
     assert(ar != NULL);
     int i;
     int j;
     int temp;
     for (i = 1; i < len; ++i)
     {
          temp = ar[i];
          for (j = i ; j >0 && ar[j-1]>temp; --j)
          {
              ar[j] = ar[j - 1];
          }
          ar[j] = temp;
     }
}

希尔排序:
递减增量排序算法,将整个待排序的记录序列分割为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对整体全体记录进行依次直接插入排序。
1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2)按增量序列个数k,对序列进行k 趟排序;
3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

//希尔排序(数组,数组长度)
void shell(int ar[], int len)
{
     assert(ar != NULL);
     int gap = 0;
     for (gap = len / 2; gap > 0; gap /= 2)
     {
          for (int i = 0; i < len; ++i)
          {
              int j = 0;
              for (j = i + gap; j < len; j += gap)
              {
                   int temp = ar[j];
                   int k = j - gap;
                   while (k >= 0 && temp < ar[k])
                   {
                        ar[k + gap] = ar[k];
                        k -= gap;
                   }
                   ar[k+gap] = temp;
              }
          }
     }
}

选择排序:
1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
2)再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
3)重复第二步,直到所有元素均排序完毕。

//选择排序
void select(int ar[], int len)
{
     assert(ar != NULL);
     int i;
     int j;
     int min;
     int temp;
     for (i = 0; i < len ; ++i)
     {
          min = i;
          for (j = i + 1; j < len; ++j)
          {
              if (ar[min]>ar[j])
              {
                   min = j;
              }

          }
          temp = ar[i];
          ar[i] = ar[min];
          ar[min] = temp;
     }
}

堆排序:
1)创建一个堆H[0..n-1]
2)把堆首(最大值)和堆尾互换
3)把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4) 重复步骤2,直到堆的尺寸为1

//堆排序
void heap(int ar[], int start, int len)
{
     int temp = ar[start];
     for (int i = 2 * start + 1; i <= len; i = 2 * i + 1)
     {
          if (i < len && (ar[i] < ar[i + 1]))
          {
              i++;
          }
          if (ar[i]>temp)
          {
              ar[start] = ar[i];
              start = i;
          }
          else
          {
              break;
          }
     }
     ar[start] = temp;
}
void myheap(int ar[], int len)
{
     assert(ar != NULL);
     for (int i = (len - 2) / 2; i >= 0; --i)
     {
          heap(ar, i, len - 1);
     }
     for (int i = 0; i < len - 1; ++i)
     {
          int temp = ar[0];
          ar[0] = ar[len - 1 - i];
          ar[len - 1 - i] = temp;
          heap(ar, 0, len - 1 - 1 - i);
     }
}

冒泡排序:
1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3)针对所有的元素重复以上的步骤,除了最后一个。
4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

//冒泡排序
void bubble(int ar[], int len)
{
     assert(ar != NULL);
     int i;
     int j;
     int temp;
     for (i = 0; i < len-1; ++i)
     {
          for (j = 0; j < len-1-i; ++j)
          {
              if (ar[j]>ar[j+1])
              {
                   temp = ar[j];
                   ar[j] = ar[j+1];
                   ar[j+1] = temp;
              }
          }
     }
}

快速排序:
1.从数列中挑出一个元素,称为 “基准”(pivot),
2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

//快速排序
int port(int ar[], int start, int end)
{
     int temp = ar[start];
     while (start<= end)
     {
          while ((start<end) && (ar[end]>=temp))
          {
              end--;
          }
          if (end<=start)
          {
              break;
          }
          else
          {
              ar[start] = ar[end];
          }
          while ((start < end) && (ar[start] <=temp))
          {
              start++;
          }
          if (start >= end)
          {
              break;
          }
          else
          {
              ar[end] = ar[start];
          }
     }
     ar[start] = temp;
     return end;
}
void quick(int ar[], int start,int end)
{
     assert(ar != NULL);
     int temp = port(ar, start, end);
     if (temp>start + 1)
     {
          quick(ar, start, temp - 1);
     }
     if (temp < end - 1)
     {
          quick(ar, temp + 1, end);
     }
}

基数排序:
将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

typedef struct Node
{
int num;
struct Node* next;
}Node,*List;

//基数排序
void initList(List head)
{
      head->next = NULL;
}
Node* getnode(int val)
{
      Node *p = (Node *)malloc(sizeof(Node));
      assert(p != NULL);
      p->num = val;
      p->next = NULL;
      return p;
}
void inserttail(List head, int val)
{
      Node* p = getnode(val);
      Node* l = head;
      while (l->next != NULL)
      {
            l = l->next;
      }
      p->next = l->next;
      l->next = p;
}
bool delfirst(List head, int *rtc)
{
      Node* p = head->next;
      if (rtc != NULL)
      {
            *rtc = p->num;
      }
      head->next = p->next;
      free(p);
      p = NULL;
      return true;
}
int getmax(int ar[], int len)
{
      int max = 0;
      for (int i = 1; i < len; ++i)
      {
            if (ar[i]>ar[max])
            {
                  max = i;
            }
      }
      cout << ar[max] << endl;
      max = ar[max];
      int num = 0;
      while (max > 0)
      {
            max /= 10;
            num++;
      }
      return num;
}
int getnum(int ar, int size)
{
      for (int i = 0; i < size; ++i)
      {
            ar /= 10;
      }
      ar %=10;
      return ar;
}
void base(int ar[], int len, int size)
{
      Node head[10];
      for (int i = 0; i < 10; ++i)
      {
            initList(&head[i]);
      }
      for (int i = 0; i < len; ++i)
      {
            int num = getnum(ar[i], size);
            inserttail(&head[num], ar[i]);
      }
      int k = 0;
      int j = 0;
      while (j < 10)
      {
            if (delfirst(&head[j], &ar[k]))
            {
                  k++;
            }
            else
            {
                  j++;
            }
      }
}
void mybase(int ar[], int len)
{
      assert(ar != NULL);
      int num = getmax(ar, len);
      cout << "num" << " " <<num<< endl;
      for (int i = 0; i < num; ++i)
      {
            base(ar, len, i);
      }
}

归并排序:
1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4. 重复步骤3直到某一指针达到序列尾
5. 将另一序列剩下的所有元素直接复制到合并序列尾

//归并排序
void merge(int ar[], int len,int i)
{
     assert(ar != NULL);
     int *p = (int *)malloc(sizeof(int)*len);
     if (p == NULL)
     {
          return;
     }
     int j = 0;
     int s1 = 0;
     int e1 = s1 + i - 1;
     int s2 = e1+1;
     int e2 = s2 + i - 1<len-1?s2+i-1:len-1;
     while (s2 < len)
     {
          while ((s1 <= e1) && (s2 <= e2))
          {
              if (ar[s1] < ar[s2])
              {
                   p[j++] = ar[s1++];
              }
              else
              {
                   p[j++] = ar[s2++];
              }
          }
          while (s1 <= e1)
          {
              p[j++] = ar[s1++];
          }
          while (s2 <= e2)
          {
              p[j++] = ar[s2++];
          }
          s1 = e2 + 1;
          e1 = s1 + i - 1;
          s2 = e1 + 1;
          e2 = s2 + i - 1 < len - 1 ? s2 + i - 1 : len -  1;
     }
     while (s1 < len)
     {
          p[j++] = ar[s1++];
     }
     for (int k = 0; k < len; ++k)
     {
          ar[k] = p[k];
     }
     free(p);
}
void mymerge(int ar[], int len)
{
     for (int i = 1; i < len; i *= 2)
     {
          merge(ar, len, i);
     }
}

数据量小时,可采用插入排序和冒泡排序,因为稳定。
数据基本处于有序时,可采用冒泡和插入或者快排,效率高。
数据量大,可采用快排,堆排序或者归并排序。
数据随机分布,时,快排的效率最高,但堆排空间复杂度低一些,若要求排序稳定可采用归并排序,若排序对内存有要求可选归并,因为读取次数最少,数据量比较大时,把数据放在磁盘上,这时要减少I/O次数-》没有特殊要求用快排。
这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值