一、概念
将一组无序的数据元素按照特定的规则(如逻辑顺序、字母顺序等)重新排列为有序序列。
1.稳定性:
在排序过程中,对于序列中两个相等的元素,如果排序前它们的相对位置为a在b之前,排序后a仍然在b之前,则称该排序算法是稳定的。否则,如果排序前后它们的相对位置为a在b之前,则称该排序算法是不稳定的。
2.内排序和外排序:
- 内部排序:数据在内存中进行排序
- 外部排序:因排序数据量太大,内存不能一次性容纳全部数据,在排序过程中需要访问外存。

二、内排序算法
1.选择排序算法
步骤:
- 初始化:将列表分为有序部分和无序部分。最开始整个序列都是无序部分。
- 查找元素:在无序部分中查找最小大的元素。
- 交换位置:将找到的最小大元素与未排序部分的第一个元素交换位置。
- 更新范围:将未排序部分的起始位置向后移动一位,扩大已排序部分的范围。
- 重复步骤:重复上述步骤,直到未排序部分为空,列表完全有序。
动画演示:

数组实现:
#include <stdio.h>
void select_Sort(int arr[],int len);
int main()
{
int arr[10]={5,1,8,3,9,11,34,90,24,6};
select_Sort(arr,10);
return 0;
}
void select_Sort(int arr[],int len)
{
int min,temp;
for (int i = 0; i < len; i++)
{
min=i; //第一个元素作为有序序列
for (int j = i; j < len; j++) //从无序序列开始
{
if(arr[min]>arr[j]) //找到比min更小的元素
{
min=j;
}
}
//进行交换
temp=arr[i];
arr[i]=arr[min];
arr[min]=temp;
}
for (int i = 0; i < len; i++)
{
printf(" %d ",arr[i]);
}
printf(" \n");
}
链表实现:
//选择排序
void select_sort(PNode head)
{
if(list_empty(head))
return;
PNode min,start , node;
start = head->next;
while (start->next != head)
{
//寻找无序部分中的最小节点
min = start;
node = start->next;
while (node != head)
{
if(node->data < min->data)
min = node;
node = node->next;
}
//将最小节点移动到无序部分开头前面
if(min != start)
mv_node(min , start->prev);
else
start = start->next;
}
}
2.插入排序
步骤:
1.初始化:将整个序列分成有序和无序两部分,最开始只有第一个元素作为有序部分,其它的都是无序部分。
2.插入:将无序部分的第一个元素start插入到有序部分。
1)从右到左找到第一个比start小的元素min。
2)将start插入到min的后面。
3.重复步骤:循环执行步骤2,直到将无序部分的所有元素都插入到有序部分中。
动画演示:

数组实现:
#include <stdio.h>
void insert_Sort(int arr[],int len);
int main()
{
int arr[10]={5,1,8,3,9,11,34,90,24,6};
insert_Sort(arr,10);
return 0;
}
void insert_Sort(int arr[],int len)
{
int start,j;
for (int i = 1; i < len; i++)
{
start=arr[i]; //作为有序序列的第一个元素
for ( j = i-1; j >=0; j--) //从右往左找到比start小的元素min(arr[j])
{
if(start>arr[j])
break;
arr[j+1]=arr[j]; //没有找到就不插入,直接往后继续
}
arr[j+1]=start;//讲=将start插入到min后面
}
for (int i = 0; i < len; i++)
{
printf(" %d ",arr[i]);
}
printf(" \n");
}
链表实现:
//插入排序
void insert_Sort(PNode head)
{
if(list_empty(head) )
return;
PNode start = head->next->next;
PNode dest , next;
while (start != head)
{
next = start->next;
//找到第一个比start大的节点
dest = head;
while (dest != start)
{
if(dest->next->data > start->data)
break;
dest = dest->next;
}
if(dest != start)
mv_node(start , dest);
start = next;
}
}
3.冒泡排序
步骤:
- 顺序:两个数据的位置符合排序需要
- 逆序:两个数据的位置不符合排序需要
遍历所有元素,让相邻两个元素比较,如果逆序,就交换两个元素的位置,否则就不动。经过一轮比较,“极值”就会被放到最后面。
动画演示:

数组实现:
#include <stdio.h>
// 1. 定义交换宏(必须)
#define SWAP(a, b) { int temp = a; a = b; b = temp; }
void bubble_Sort(int arr[], int len);
int main()
{
int arr[]={5,1,8,3,9,11,34,90,24,6};
int len = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
bubble_Sort(arr,len);
printf(" 排序后的数组:\n");
for (int i = 0; i < len; i++)
{
printf(" %d ",arr[i]);
}
printf(" \n");
return 0;
}
//冒泡排序
void bubble_Sort(int arr[] , int len)
{
for (int i = 0; i < len; i++) //完成一轮排序
{
for(int j=0 ; j<len-1-i; j++)
{
if(arr[j] > arr[j+1]) //逆序
{
SWAP(arr[j] , arr[j+1]) //交换两个逆序的元素
}
}
}
}
链表实现:
//冒泡排序
void bubble_Sort(PNode head)
{
if(list_empty(head) )
return;
int len =0;
bool change;
PNode node = head->next;
while (node != head){
len++;
node = node->next;
}
for (int i = 0; i < len; i++){
change =false;
node = head->next;
for(int j=0 ; j<len-i-1 ; j++){
if(node->data > node->next->data){
change = true;
mv_node(node , node->next);
}
else
node = node->next;
}
if(!change)
break;
}
}
4.希尔排序
是插入排序的优化。
步骤:
- 选择一个不序列长度len小的数字gap作为间距(步长、增量)
- 以gap进行分组
- 在各小组内部进行插入排序
- 再将gap减小,重新分组,并在各小组内部进行插入排序
- 直到gap小于等于1为止
动画演示
数组实现:
#include <stdio.h>
void shell_insert(int arr[],int count,int gap); //插入
void shell_Sort(int arr[] , int len);
int main()
{
int arr[10]={5,1,8,3,9,11,34,90,24,6};
shell_Sort(arr,10);
return 0;
}
/*
对分组内部进行插入排序
arr:小组的起点
count:小组长度
gap:步长
*/
void shell_insert(int arr[],int count,int gap)
{
if(count<=1)
return;
int start ,j;
for(int i = gap ; i< count * gap ; i+= gap)
{
start = arr[i];
for(j = i-gap ;j>=0 ; j-=gap)
{
if(arr[j] < start)
break;
arr[j+gap] = arr[j];
}
arr[j+gap] = start;
}
}
//希尔排序
void shell_Sort(int arr[] , int len)
{
//分组
for (int gap = len/2; gap > 0 ; gap/=2)
{
for (int i = 0; i < gap; i++) //对每个小组进行排序
{
shell_insert(arr+i , len/gap , gap);
}
}
for (int i = 0; i < len; i++)
{
printf(" %d ",arr[i]);
}
printf(" \n");
}
5.快速排序
步骤:
-
从序列中挑选一个元素,作为基准key,一般是最左边(升序)或最右边(降序)的元素
-
进行一轮排序
i·定义一个left和right,left从左往右走,right从右往左走
ii.走的过程中,如right遇到比key小的元素就停下来;若left遇到比key大的元素就停下来
ii交换left和right所在位置的元素,交换后,继续相向而行
iv.直到left和right相遇,交换key和相遇点的值
-
以key分成左右两部分,左边的都是比key小的,右边的都是比key大的
-
递归地对左右两部分分别进行快速排序
动画演示:

数组实现:
#include <stdio.h>
// 1. 定义交换宏(必须)
#define SWAP(a, b) { int temp = a; a = b; b = temp; }
void quick_Sort(int arr[] , int left , int right);
int main()
{
int arr[]={5,1,8,3,9,11,34,90,24,6};
int len = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
quick_Sort(arr,0,len-1);
printf(" 排序后的数组:\n");
for (int i = 0; i < len; i++)
{
printf(" %d ",arr[i]);
}
printf(" \n");
return 0;
}
//快速排序
void quick_Sort(int arr[] , int left , int right)
{
if(left >= right)
return;
int key = arr[left]; //比较基准
int l = left;
int r = right;
//进行一轮排序,退出条件就是l和r相遇
while(l<r){
//r从右往左走,遇到比key小的元素就停下来
while (l<r && arr[r] >= key){
r--;
}
//l从左往右走,遇到比key大的元素就停下来
while (l<r && arr[l] <= key){
l++;
}
if(l<r){
SWAP(arr[l] ,arr[r])
}
}
//交换key和相遇点的值
arr[left] = arr[l];
arr[l] = key;
//d.递归地对左右两部分分别进行快速排序
quick_Sort(arr , left , l-1);
quick_Sort(arr , l+1 , right);
}
三、应用场景
排序算法的种类和应用场景如下:
-
冒泡排序:适用于待排序序列元素个数较少,或对稳定性要求较高的场景。
-
快速排序:适用于待排序序列元素个数较多,且元素分布比较均匀的场景。
-
选择排序:适用于待排序序列元素个数较少,或对稳定性要求较高的场景。
-
插入/希尔排序:适用于待排序序列元素个数较少,或元素基本有序的场景。
1044

被折叠的 条评论
为什么被折叠?



