前言
这是我听老师讲课做的笔记,考试要看的。
作者:RodmaChen
关注我的csdn博客,更多数据结构与算法知识还在更新
内部排序算法
数据结构核心原理与算法应用
一.基本概念
- 内部排序 :是指待排序记录存放在计算机随机存储器中进行的排序过程。
- 外部 排序: 是指待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程.
- 排序的稳定性:假设ki=kj, 且排序前序列中Ri领先于Rj,若在排序后的序列中Ri仍领先于Rj,则称排序方法是稳定,否则称为不稳定的。
- 排序时间复杂性:排序过程主要是对记录的关键码进行比较和记录的移动,所以排序的时间复杂性以算法的执行中数据比较次数和数据移动的次数来衡量。
二.插入排序
基本思想:将一个元素记录按其应用的位置插入到已排好序的序列中。
依据寻找插入位置的方法不同,插入排序分为:直接插入排序;折半插入排序;希尔插入排序;表插入排序。
1.直接插入排序
基本思想三步骤:找位置,搬动,插入
例 :某组记录的初始排列如下:49 38 65 97 76 13 27 49
算法执行过程(括号内括的表示有序区):
初始关键字 R[0] (49) 38 65 97 76 13 27 49
i=2: (38) (38 49) 65 97 76 13 27 49
i=3: (65) (38 49 65) 97 76 13 27 49
i=4: (97) (38 49 65 97) 76 13 27 49
i=5: (76) (38 49 65 76 97) 13 27 49
i=6: (13) (13 38 49 65 76 97) 27 49
i=7: (27) (13 27 38 49 65 76 97) 49
i=8: (49) (13 27 38 49 49 65 76 97)
算法实现:
void InsertSort(SqList *L)
{ int i,j=0,k,temp;
for(i=1;i<L->length;i++)
{ temp=L->data[i];
while(temp>=L->data[j]&&j<=i-1)
j++;
for(k=i-1;k>=j;k--)
L->data[k+1]=L->data[k];
L->data[j]=temp;
}
}
时间复杂度O(n ² )
辅助空间O(1)
稳定
2. 二分法插入排序
直接排序用的是顺序查找,这是用折半查找(二分查找)
例 :某有序序列如下,插入28
3 8 15 46 75
void BinInsertSort(SqList &L) // 对顺序表L作折半插入排序
{ int low,high,mid,i,j,temp;
for(i=1; i<L->length; i++)
{ temp=L->data[i];
low=0; high=i-1;
while(low<=high)
{ mid=(low+high)/2;
if(temp>=L->data[mid])
low=mid+1;
else
high=mid-1;
}
for(j=i-1;j>=low;j--)
{ L->data[j+1]=L->data[j]; }
L->data[low]=temp;
}
}
3.希尔排序(缩小增量):不常考
先将待排序记录序列分割成若干序列,分别进行直接
插入排序;待整个序列中的记录基本有序后,再全体进
行一次直接插入排序。
2 、例:假设待排序文件有10个记录,其关键字分别是:49,38,65,97,76,13,27,49,55,04。
增量序列的取值依次为:5,3,1
初始化关键字:分两组比较
第一趟:分三组比较
第二趟:直接排序
时间复杂度:O((logⁿ)²)
不稳定:前面分组是跳着抽的
三.交换排序
1.冒泡排序
1 .基本思想
通过不断比较相邻元素大小,进行交换实现排序。
第一趟排序:
首先将第一个元素和第二个元素比较大小,若为逆序,则交换;然后比较第二个与第三个,一直到第n-1和第n个,这样就使最大的元素放到了最后一个位置。(每一趟比较出最大的数放到最后面)
2.示例
算法实现
void BubbleSort(SqList *L)
{ for(int i=1; i<L->length; i++)
{ flag=1;
for(j=1;j<L->length-i;j++)
{ if(L->data[j] > L->data[j+1])
{ temp= L->data[j];
L->data[j]= L->data[j+1];
L->data[j+1]=temp;
flag=0;} }
if (flag=1) break;
}
}
效率分析
最好情况正序:只需要比较
n-1
次比较,0
次移动最坏情况逆序:就需要进行
n-1
趟,时间复杂度
O(n² )
辅助空间
O(1)
稳定
2.快速排序(难)
1 、基本思想
以某个记录为界(支点或枢轴),将待排序列分成两部分,一部分所有记录的关键码小于支点记录的关键码,而另一部分大于支点的关键码。然后对每一部分再划分,直至整个序列有序。
轴在高位跟低位比,在低位就跟高位比
int Partition(SqList &L, int low, int high) /*一趟快排序*/
{ temp=L->data[0];
low=0; high=L->length-1;
while(low<high)
{ //轴在低位
while(low<high&& L->data[high]>=temp) high--;
if(L->data[high]<temp)
{ L->data[low]= L->data[high];
low++;
}
//轴到高位
while(low<high&& L->data[low]<=temp) low++;
if(L->data[low]>temp)
{
L->data[high]= L->data[low];
high--;
}
}
}
时间复杂度:nlog₂n
空间复杂度:log₂n
四.选择排序
选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。
常用的选择排序方法有简单选择排序和堆排序。
1.简单选择排序
基本思想
第一趟:从
n
个记录中找出关键字最小的记录与第一个记录交换;第二趟:从第二个记录开始的
n-1
个记录中再选出关键码最小的记录与第二个记录交换;第i趟:则从
第i个
记录开始的n-i+1
个记录中选出关键字最小的记录与第i个记录交换,直到整个序列按关键字有
序。这种操作进行
n-1
次,但每一次的待排元素个数比上一次少一个。
下图所示:
3 、算法
void SelectSort(SqList &L)
{
for(i=0;i<=L->length-1;i++)
{ min=i; //假设最小值下标为i
for(j=i+1; j<L->length-1; j++)
if(L->data[min]>L->data[j])
min=j;
if(i!=min) //
{ temp=L->data[i];
L->data[i]=L->data[min];
L->data[min]=temp;
}
}
时间复杂度O(n 2 )
空间效率:O(1)
不稳定
2. 堆排序
定义
n
个关键字序列K₁,K₂,…,Kn
称为堆,当且仅当该序列满足如下性质(简称为堆性质):
例如:{96,83,24,38,11,09}
{12,36,24,85,47,30,53,91}
基本思想
• 将序列构造成一棵完全二叉树
• 把这棵普通的完全二叉树改造成堆,便可获取最小值(最大值)
• 输出最小(大)值
• 将最后一个结点放到输出结点的位置,再次改造,直至输出所有结点
效率分析
时间复杂度O(nlog ₂n))
空间效率:O(1)
不稳定
五.归并排序
基本思想
(1)把n个记录看成n个长度为l
的有序子表;
(2)进行两两归并使记录关键字有序, 得到[n/2]
个长度为2
的有序子表;
(3)重复第(2)步, 直到所有记录归并成一个长度为n的有序表为止。
例: 有一组关键字{4,7,5,3,2,8,6,1}, n=8, 将其按由小到大的顺序排序。
两路归并排序操作过程如下, 其中l为子表长度。
初始 [4] [7] [5] [3] [2] [8] [6] [1] l=1
第 1 趟[4 7] [3 5] [2 8] [1 6] l=2
第 2 趟[3 4 5 7] [1 2 6 8] l=4
第 1 趟[1 2 3 4 5 6 7 8] l=n
空间复杂度:O(n)
时间复杂度:O(nlog₂n)
稳定
六.各种内部排序比较
七.边学边练
-
一趟快速排序具体做法:25,7,13,38,23,46,17, 49,39
-
以关键字序列(42,31,75,63,25,38)为例,
分别写出执行以下排序算法的各趟排序结束时,关键字序
列的状态。
(1)直接插入排序 (2)二分法插入排序
(3)希尔排序(增量取3,2,1)
(4)冒泡排序
(5)快速排序(一趟)
(6)简单选择排序 (7)两路归并排序
本人博客:https://blog.csdn.net/weixin_46654114
本人b站求关注:https://space.bilibili.com/391105864
转载说明:跟我说明,务必注明来源,附带本人博客连接。
请给我点个赞鼓励我吧