1、排序:重排表中元素。

2、根据数据元素是否完全在内存中,将排序算法分为内部排序和外部排序两类。

3、插入排序:将一个待排序记录按关键字大小插入到前面已排好的子序列中,直到全部记录插入完成。

1)直接插入排序

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];
   L.r[i] = L.r[i - 1];
   for (j = i - 2; L.r[0].key < L.r[j].key; --j)
   {
    L.r[j + 1] = L.r[j];
   }
   L.r[j + 1] = L.r[0];
  }
 }
}

(1)空间复杂度为O(1);时间复杂度为O(n2)。

(2)稳定性:插入元素时总是从后向前先比较后移动,不会出现相同元素相对位置发生变化,为稳定算法。

(3)适用性:适用于顺序存储和链式存储的线性表。

2)折半插入排序

void insertsort2(sqlist L)
{
 int i, j, low, high, mid;
 for (i = 2; i < L.length; i++)
 {
  L.r[0] = L.r[i];
  low = 1;
  high = i - 1;
  while (low<=high)
  {
   mid = (low + high) / 2;
   if (L.r[mid].key > L.r[0].key)
   {
    high = mid - 1;
   }
   else
   {
    low = mid + 1;
   }
  }
  for (j = i - 1; j >= high + 1; --j)
  {
   L.r[j + 1] = L.r[j];
  }
  L.r[high + 1] = L.r[0];
 }
}

(1)折半查找找出元素待插入的位置,统一地移动待插入位置之后的所有元素。

(2)时间复杂度为O(n2)。

(3)稳定性:为稳定算法。

3)希尔排序(缩小增量排序)

void insertsort3(sqlist L)
{
 int i, j,k;
 for (j = L.length / 2; j >= 1; j = j / 2)
 {
  for (i = j + 1; i <= L.length; ++i)
  {
   if (L.r[i].key < L.r[i - j].key)
   {
    L.r[0] = L.r[i];
    for (k = i - j; k > 0 && L.r[0].key < L.r[k].key; k -= j)
    {
     L.r[k + j] = L.r[k];
    }
    L.r[k + j] = L.r[0];
   }
  }
 }
}

(1)将待排序表分割成若干个子表,分别进行直接插入排序,当表中元素节本有序时,对整个表进行一次直接插入排序。

(2)空间复杂度为O(1);时间复杂度约为O(n1-2),最坏情况下时间复杂度为O(n2)。

(3)稳定性:不稳定。

(4)适用性:仅适用于顺序存储的线性表。

4、交换排序

1)冒泡排序

void bubblesort(sqlist L)
{
 int i, j, temp;
 bool flag;//发生交换的标志
 for (i = 0; i < L.length-1; i++)
 {
  flag = false;
  for (j = L.length - 1; j > i; j--)
  {
   if (L.r[j - 1].key > L.r[j].key)
   {
    temp = L.r[j - 1].key;
    L.r[j - 1].key = L.r[j].key;
    L.r[j].key = temp;
    flag = true;
   }
  }
  if (flag == false)
  {
   return;
  }
 }
}

(1)从后向前两两比较相邻元素的值,若为逆序则交换。

(2)空间复杂度为O(1);平均时间复杂度为O(n2),最坏情况下时间复杂度为O(n2)。

(3)稳定性:稳定。

(4)双向起泡排序。奇数趟时,从前向后比较相邻元素的关键字,逆序则交换;偶数趟时,从后向前比较相邻元素的关键字,逆序则交换。

void bubblesort2(sqlist L)
{
 int low = 0, high = L.length;
 bool flag = true;
 int temp;
 while (low<high&&flag)
 {
  flag = false;
  for (int i = low; i < high; i++)
  {
   if (L.r[i].key > L.r[i + 1].key)
   {
    temp = L.r[i].key;
    L.r[i].key = L.r[i+1].key;
    L.r[i+1].key = temp;
    flag = true;
   }
  }
  high--;
  for (int i = high; i >low; i--)
  {
   if (L.r[i].key < L.r[i - 1].key)
   {
    temp = L.r[i].key;
    L.r[i].key = L.r[i - 1].key;
    L.r[i - 1].key = temp;
    flag = true;
   }
  }
  low++;
 }
}

2)快速排序

int partition(sqlist L, int low, int high)
{
 int pivotkey;
 L.r[0] = L.r[low];
 pivotkey = L.r[low].key;
 while (low<high)
 {
  while (low<high&&L.r[high].key>=pivotkey)
  {
   --high;
  }
  L.r[low] = L.r[high];
  while (low < high&&L.r[low].key <= pivotkey)
  {
   ++low;
  }
  L.r[high] = L.r[low];
 }
 L.r[low] = L.r[0];
 return low;
}
void quicksort(sqlist L,int low,int high)
{
 if (low < high)
 {
  int pos = partition(L, low, high);
  quicksort(L, low, pos - 1);
  quicksort(L, pos + 1, high);
 }
}

(1)最坏情况空间复杂度为O(n),平均空间复杂度为O(log2n);平均时间复杂度为O(nlog2n),最坏情况下时间复杂度为O(n2)。

(2)所有内部排序中平均性能最优的排序算法。

5、选择排序

每一趟在后面n-i+1个待排序元素中选取关键字最小的元素,作为有序序列的第i个元素,直到第n-1趟做完,待排序元素只剩一个。

1)简单选择排序

void selectsort(sqlist L)
{
 int i, j, min,temp;
 for (i = 0; i < L.length - 1; i++)
 {
  min = i;
  for (j = i + 1; j < L.length; j++)
  {
   if (L.r[j].key < L.r[min].key)
   {
    min = j;
   }
  }
  if (min != i)
  {
   temp = L.r[i].key;
   L.r[i].key = L.r[min].key;
   L.r[min].key = temp;
  }
 }
}

(1)空间复杂度为O(1);时间复杂度为O(n2)。

(2)稳定性:不稳定。

2)堆排序

void adjustdown(sqlist L,int k)//将元素向下调整
{
 L.r[0].key = L.r[k].key;
 for (int i = 2 * k; i <= L.length; i *= 2)
 {
  if (I < L.length&&L.r[i].key < L.r[i + 1].key)
  {
   i++;
  }
  if (L.r[0].key >= L.r[i].key)
  {
   break;
  }
  else
  {
   L.r[k].key = L.r[i].key;
   k = i;
  }
 }
 L.r[k].key = L.r[0].key;
}

时间复杂度与树高(h)有关,为O(h)。
void adjustup(sqlist L, int k)//将元素向上调整
{
 L.r[0].key = L.r[k].key;
 int i = k / 2;
 while (i>0&& L.r[i].key < L.r[0].key)
 {
  L.r[k].key = L.r[i].key;
  k = i;
  i = k / 2;
 }
 L.r[k].key = L.r[0].key;
}

void buildmaxheap(sqlist L)//建立大根堆
{
 for (int i = L.length / 2; i > 0; i--)
 {
  adjustdown(L, i);
 }
}

在n个元素序列上建堆,时间复杂度为O(n)。
void heapsort(sqlist L)
{
 buildmaxheap(L);
 int temp;
 for (int i = L.length; i > 1; i--)
 {
  temp = L.r[i].key;
  L.r[i].key = L.r[1].key;
  L.r[1].key = temp;
  adjustdown(L, 1);
 }
}

(1)一种树形选择排序,在排序过程中,将L视为一棵完全二叉树的顺序存储结构。

(2)最大堆:堆顶元素取最大值;最小堆:栈顶元素为最小值。

(2)空间复杂度为O(1);时间复杂度为O(nlog2n)。

(3)稳定性:不稳定。

6、归并排序

1)归并:将两个或两个以上的有序表组合成一个新的有序表。

2)2路归并排序

void merge(sqlist A, int low, int mid, int high)
{
 sqlist B;
 int i, j, k;
 for (k = low; k <= high; k++)
 {
  B.r[k].key = A.r[k].key;
 }
 for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++)
 {
  if (B.r[i].key <= B.r[j].key)
  {
   A.r[k].key <= B.r[i++].key;
  }
  else
  {
   A.r[k].key <= B.r[j++].key;
  }
 }
 while (i<=mid)
 {
  A.r[k++].key <= B.r[i++].key;
 }
 while (j <= high)
 {
  A.r[k++].key <= B.r[j++].key;
 }
}
void mergesort(sqlist L, int low, int high)
{
 if (low < high)
 {
  int mid = (low + high) / 2;
  mergesort(L, low, mid);
  mergesort(L, mid + 1, high);
  merge(L, low, mid, high);
 }
}

(1)假定带排序表含有n个记录,则将其视为n个有序的子表,每个子表长度为1,然后两两归并,得到n/2个长度为2或1的有序表,再两两归并,直到合并成一个长度为n的有序表为止。

(2)空间复杂度为O(n);时间复杂度为O(nlog2n)。

(3)稳定性:稳定。

7、基数排序

(1)分类:最高位优先(MSD)、最低位优先(LSD)。

(2)一趟排序需要辅助存储空间为r,空间复杂度为O(r);基数排序需要进行d趟分配和收集,一趟分配需要O(n),一趟收集需要O(r),故基数排序时间复杂度为O(d(n+r)),与序列的初始状态无关。

(3)稳定性:稳定。

8、内部排序的比较

算法种类 时间复杂度 空间复杂度 是否稳定
最好情况 平均情况 最坏情况
直接插入排序 O(n) O(n2) O(n2) O(1)
冒泡排序 O(n) O(n2) O(n2) O(1)
简单选择排序 O(n2) O(n2) O(n2) O(1)
希尔排序       O(1)
快速排序 O(nlog2n) O(nlog2n) O(n2) O(log2n)
堆排序 O(nlog2n) O(nlog2n) O(nlog2n) O(1)
2路归并排序 O(nlog2n) O(nlog2n) O(nlog2n) O(n)
基数排序 O(d(n+r)) O(d(n+r)) O(d(n+r)) O(r)
折半插入排序 O(n2) O(n2) O(n2) O(1)

9、排序小结

1)n较小,采用直接插入排序或简单选择排序。

2)初始状态基本有序,采用直接插入排序或冒泡排序。

3)n较大,采用快速排序、堆排序、归并排序。

4)n较大,关键字位数较少,且可分解,采用基数排序。

10、外部排序通常采用归并排序方法。

1)外部排序所需总时间=内部排序所需时间+外存信息读写时间+内部归并所需时间

2)多路平衡归并

(1)败者树:完全二叉树且不含叶子,可采用顺序存储结构。

3)置换-选择排序:在整个排序过程中,选择最小(或最大)关键字和输入、输出交叉或平行进行。

4)最佳归并树

数据结构(C语言版)---排序的更多相关文章

  1. 数据结构C语言版 表插入排序 静态表

    数据结构C语言版 表插入排序.txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了.他只是比对方更珍惜这份感情./*  数据结构C语言版 表插入排序  算法10.3 P267-P270  编译 ...

  2. c++学习书籍推荐《清华大学计算机系列教材:数据结构(C++语言版)(第3版)》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <清华大学计算机系列教材:数据结构(C++语言版)(第3版)>习题解析涵盖验证型.拓展型.反思型.实践型和研究型习题,总计290余道大题.525道 ...

  3. 数据结构C语言版 有向图的十字链表存储表示和实现

    /*1wangxiaobo@163.com 数据结构C语言版 有向图的十字链表存储表示和实现 P165 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h> ...

  4. 数据结构C语言版 弗洛伊德算法实现

    /* 数据结构C语言版 弗洛伊德算法  P191 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h>#include <limits.h> # ...

  5. 《数据结构-C语言版》(严蔚敏,吴伟民版)课本源码+习题集解析使用说明

    <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明 先附上文档归类目录: 课本源码合辑  链接☛☛☛ <数据结构>课本源码合辑 习题集全解析  链接☛☛☛  ...

  6. 深入浅出数据结构C语言版(17)——有关排序算法的分析

    这一篇博文我们将讨论一些与排序算法有关的定理,这些定理将解释插入排序博文中提出的疑问(为什么冒泡排序与插入排序总是执行同样数量的交换操作,而选择排序不一定),同时为讲述高级排序算法做铺垫(高级排序为什 ...

  7. 深入浅出数据结构C语言版(17)——希尔排序

    在上一篇博文中我们提到:要令排序算法的时间复杂度低于O(n2),必须令算法执行"远距离的元素交换",使得平均每次交换减少不止1逆序数. 而希尔排序就是"简单地" ...

  8. 深入浅出数据结构C语言版(21)——合并排序

    在讲解合并排序之前,我们先来想一想这样一个问题如何解决: 有两个数组A和B,它们都已各自按照从小到大的顺序排好了数据,现在我们要把它们合并为一个数组C,且要求C也是按从小到大的顺序排好,请问该怎么做? ...

  9. 深入浅出数据结构C语言版(22)——排序决策树与桶式排序

    在(17)中我们对排序算法进行了简单的分析,并得出了两个结论: 1.只进行相邻元素交换的排序算法时间复杂度为O(N2) 2.要想时间复杂度低于O(N2),算法必须进行远距离的元素交换 而今天,我们将对 ...

  10. 数据结构(C语言版)严蔚敏->排序

    @ 目录 1. 插入排序 1.1 直接插入排序 1.2 折半插入排序 1.3 希尔排序(Shell Sort) 2.交换排序 2.1 冒泡排序 2.2 快速排序 3. 选择排序 3.1 简单选择排序 ...

随机推荐

  1. Prism 源码解读7-导航

    介绍 Prism提供了一个非常强大的功能导航,导航的意思就是指定对应的View显示.这个导航的强大之处有: 可以设置导航前后的动作 可以指定View实例的生命周期,可以是否导航到新的View实例 提供 ...

  2. Mac OS修改VSCode Go的默认缩进格式

    一.在VSCode中编写Go代码时,缩进是使用tab缩进,主要是由于以下两个方面. 1. Go官方提供的代码格式化工具gofmt默认是使用tab缩进,并且为8个字符宽度. 2. 并且在VSCode中, ...

  3. 原生js判断手机端页面滚动停止

    var topValue = 0,// 上次滚动条到顶部的距离 interval = null;// 定时器 contactsList = document.getElementById(" ...

  4. 新建jsp文件,The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path错误解决方法

    新建一个jsp文件后,有一个错误,The superclass "javax.servlet.http.HttpServlet" was not found on the Java ...

  5. 基于Taro.js和微信小程序云开发的移动端校园平台——《我的衡师》

    我学校教务处目前仅有电脑端,并不适配移动端,电脑端也只能使用IE6浏览器访问,兼容性差.我在没有api接口的情况下,通过Carles和Postman抓包,用node.js爬虫实现了后台和小程序的对接. ...

  6. 浅谈头文件(.h)和源文件(.cpp)的区别

    浅谈头文件(.h)和源文件(.cpp)的区别 本人原来在大一写C的时候,都是所有代码写在一个文件里一锅乱煮.经过自己开始写程序之后,发现一个工程只有一定是由多个不同功能.分门别类展开的文件构成的.一锅 ...

  7. PTA | 1016 部分A+B (15分)

    正整数 A 的"DA(为 1 位整数)部分"定义为由 A 中所有 DA 组成的新整数 PA.例如:给定 A=3862767,DA=6,则 A 的"6 部分"PA ...

  8. 【PHP】函数

    一.      数学中的函数: a)    sin().cos().tan().log() 这些都是数学函数,但是都已经忘了啥意思了!没关系,在php当中的函数和这些函数的概念还是有一定的区别的 二. ...

  9. flask-宏

    flask-宏 模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量,使用宏的时候,参数可以为默认值. ...

  10. django类视图的装饰器验证

    django类视图的装饰器验证 django类视图的get和post方法是由View内部调用dispatch方法来分发,最后调用as_view来完成一个视图的流程. 函数视图可以直接使用对应的装饰器 ...