在数据结构中,排序有以下几种分类:
(1)按存储位置分为内部排序和外部排序;
(2)按排序算法或者逻辑分为插入排序、选择排序、交换排序、归并排序和基数排序;
(3)按排序结果分为升序和降序。
说到排序就可以说到稳定性。稳定性我们可以理解为:在待排序数字中的重复数据,在排序前后的相对前后位置不变。
其中,
稳定的有:直接插入排序、冒泡排序、归并排序、基数排序
不稳定的有:Shell排序、选择排序(直接选择排序、堆排序)、快速排序
直接插入排序
代码实现
#include<stdio.h>
void InsertSort(int *arr, int len)
{
int i;
int j;
for (i=2;i<len;i++)
{
arr[0] = arr[i];
for (j=i-1;arr[j]>arr[0];j--)
{
arr[j + 1] = arr[j];
}
arr[j + 1] = arr[0];
}
}
时间复杂度 :O(n^2)
空间复杂度:O(1)
代码测试
int main()
{
int arr[] = { -1,55,1,3,11,5,8,6,25,14,47};
int len = sizeof(arr) / sizeof(arr[0]);
InsertSort(arr, len);
return 0;
}
Shell(希尔)排序
代码实现
#include<stdio.h>
void Shell(int *arr, int len,int dk)
{
int i;
int j;
int tmp;
for (i=dk;i<len;i++)
{
tmp = arr[i];
for (j=i-dk;j>=0 && arr[j]>tmp;j=j-dk)
{
arr[j + dk] = arr[j];
}
arr[j + dk] = tmp;
}
}
void shellSort(int *arr,int arr_len,int *dka,int dka_len)
{
for (int i=0;i<dka_len;i++)
{
Shell(arr,arr_len,dka[i]);
}
}
时间复杂度 :O(n^2)
空间复杂度:O(1)
函数测试
int main()
{
int arr[] = { 55, 2, 44, 6, 8, 32, 46, 4, 26};
int dka[] = {5,3,1};
int arr_len = sizeof(arr) / sizeof(arr[0]);
int dka_len = sizeof(dka) / sizeof(dka[0]);
ShellSort(arr, arr_len, dka, dka_len);
return 0;
}
选择排序:
①简单选择排序
②堆排序
①代码实现
#include<stdio.h>
void SelectSort(int *arr, int len)
{
int i;
int j;
int min;
int tmp;
for (int i=0;i<len-1;i++)
{
min = i;
for (j=i+1;j<len;j++)
{
if (arr[j] < arr[min])
{
min = j;
}
}
tmp = arr[min];
arr[min] = arr[i];
arr[i] = tmp;
}
}
时间复杂度 :O(n^2)
空间复杂度:O(1)
函数测试
int main()
{
int arr[] = {1,5,6,8,6,5,85,9,6,1};
int len = sizeof(arr) / sizeof(arr[0]);
SelectSort(arr, len);
return 0;
}
②堆排序
大根堆(升序):父节点的数据大于子节点的数据。
父节点找子节点:i=1, 左子树 j=2*i,右子树j=2*i=1
子节点找父节点:j=5,i=j/2
小根堆:降序
代码测试
#include<stdio.h>
/*找到最后一个有子节点的父节点:len/2;找到较大的子节点数与父节点上的数据比较,如果子节点上的数大于父节点的,那么将两者数据交换;调整完一遍之后将最顶端的数字与最后一个数字交换,最后一个数字不用再进入比较*/
void HeapAdjust(int *arr, int i, int len)
{
int j; //j <= len 有左子树
for (j=2*i;j<=len;j=2*j)
{
if (j<len && arr[j]<arr[j + 1])
{
j++;
}
if (arr[j] < arr[i])
{
break;
}
arr[0] = arr[i];
arr[i] = arr[j];
arr[j] = arr[0];
i = j;
}
}
void HeapSort(int *arr, int len)
{
int tmp;
for (int i=len/2;i>0;i--)
{
HeapAdjust(arr,i,len);
}
for (int j=len;j>0;j--)
{
tmp = arr[1];
arr[1] = arr[j];
arr[j] = tmp;
HeapAdjust(arr,1,j-1);
}
}
时间复杂度 :O(log2n)
空间复杂度:O(1)
函数测试
int main()
{
int arr[] = {516,8,154,8,44,52,821,56,42};
int arr1[] = {215,48,20,8,632,8,865,1};
int len = sizeof(arr)/sizeof(arr[0]) -1;
HeapSort(arr,len);
return 0;
}
交换排序:
①冒泡排序
②快速排序
①代码实现
#include<stdio.h>
void BubbleSort(int *arr,int len)
{
int tmp;
bool mark = false;
for (int i=0;i<len-1;i++)
{
mark = false;
for (int j=0;j<len-1-i;j++)
{
if (arr[j]>arr[j+1])
{
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
mark = true;
}
}
printf("i = %d\n",i);
if (!mark)
{
break;
}
}
}
时间复杂度 :O(n^2)
空间复杂度:O(1)
代码测试
int main()
{
int arr[] = {8,651,686,51,52,64,65,85,16,516};
int len = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, len);
return 0;
}
②代码实现
int Partition(int *arr,int low,int high)
{
int tmp = arr[low];
while(low < high)
{
while (low < high && arr[high] >= tmp)high--;
arr[low] = arr[high];
while (low < high && arr[low] <= tmp)low++;
arr[high] = arr[low];
}
arr[low] = tmp;
return low;
}
void QSort(int *arr,int low,int high)
{
if (low < high)
{
int boundKey = Partition(arr,low, high);
QSort(arr, low, boundKey - 1);
QSort(arr, boundKey+1, high);
}
}
void QuickSort(int *arr,int len)
{
QSort(arr,0,len-1);
}
时间复杂度 :O(n^2)
空间复杂度:O(nlog2n)
代码测试
int main()
{
int arr[] = {65,46,548,68,19,5,6,56,569};
int len = sizeof(arr) / sizeof(arr[0]);
QuickSort(arr,len);
printf("\n");
return 0;
}
归并排序
代码实现
#include<stdio.h>
void Merge(int *arr,int *tmp,int StartIndex,int MidIndex,int EndIndex)
{
int i = StartIndex;
int j = MidIndex + 1;
int k = StartIndex;
while (i != MidIndex + 1 && j != EndIndex + 1)
{
if (arr[i] > arr[j])
{
tmp[k++] = arr[j++];
}
else
{
tmp[k++] = arr[i++];
}
}
while (i != MidIndex + 1)
{
tmp[k++] = arr[i++];
}
while (j != EndIndex + 1)
{
tmp[k++] = arr[j++];
}
for (int i=StartIndex;i <= EndIndex; i++)
{
arr[i] = tmp[i];
}
}
void MergeSort(int *arr,int *tmp,int StartIndex,int EndIndex)
{
if (StartIndex < EndIndex)
{
int MidIndex = (StartIndex + EndIndex) / 2;
MergeSort(arr,tmp,StartIndex,MidIndex);
MergeSort(arr,tmp,MidIndex + 1,EndIndex);
Merge(arr,tmp,StartIndex,MidIndex,EndIndex);
}
}
时间复杂度 :O(nlog2n)
空间复杂度:O(n)
代码测试
#define N 12
int main()
{
int arr[12] = {2,85,1,65,6,16,32,15,88,964,53,4};
int len = sizeof(arr) / sizeof(arr[0]);
int tmp[N];
MergeSort(arr,tmp,0,len-1);
return 0;
}
基数排序
将待排序数列分别根据个位、十位、百位排序:
代码实现
#include<stdio.h>
#include<math.h>
#define N 14
int FindMaxFinger(int *arr, int len)//找到最大数是几位数
{
int max = arr[0];
for (int i=1;i<len;i++)
{
if (arr[i] > max)
{
max = arr[i];
}
}
int count = 0;
while(max != 0)
{
max = max/10;
count++;
}
return count;
}
//每个数据分别在个、十、百位上的数
int FindFingerNumber(int num, int fin)
{
return num/(int)pow(10.0,fin) % 10;
}
void Radix(int *arr, int len, int fin)
{
int tmp[10][N] = {};
int num_fin;
int count[10] = {};
for (int i=0;i<len;i++)
{
num_fin = FindFingerNumber(arr[i],fin);
tmp[num_fin][count[num_fin]] = arr[i];
count[num_fin]++;
}
int index = 0;
for (int i=0;i<10;i++)
{
for (int j=0;j<count[i];j++)
{
arr[index++] = tmp[i][j];
}
}
}
void RadixSort(int *arr, int len)
{
int MaxFinNum = FindMaxFinger(arr,len);
for (int i=0;i<MaxFinNum;i++)
{
Radix(arr,len,i);
}
}
时间复杂度 :O(d(r+n))
空间复杂度:O(rd+n)
代码测试
int main()
{
int arr[N] = {5,51,3,541,351,56,5165,1,651};
int len = N;
RadixSort(arr,len);
return 0;
}
链表排序
代码实现
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int val; //有效数据长度
Node* pNext;
}Node;
void Init(Node **head)
{
*head = (Node*)malloc(sizeof(Node));
if (*head == NULL)exit(0);
(*head)->pNext = NULL;
(*head)->val = 0;
}
void Insert(Node *head, int data)
{
Node* pCur = head;
for (int i=0;i < head->val;i++)
{
pCur = pCur->pNext;
}
Node *NewNode = (Node*)malloc(sizeof(Node));
if (NewNode != NULL)
{
pCur->pNext = NewNode;
NewNode->pNext = NULL;
NewNode->val = data;
head->val++;
}
}
void Show(Node *head)
{
Node *pCur = head->pNext;
for (int i=0;i<head->val;i++)
{
printf("%d ", pCur->val);
pCur = pCur->pNext;
}
printf("\n");
}
void ListSort(Node* head)
{
Node* pCur;
Node* pAfter;
for (int i = 0; i < head->val - 1; ++i)
{
pCur = head->pNext;
pAfter = pCur->pNext;
for (int j = 1; j < head->val - i; ++j)
{
if (pCur->val > pAfter->val)
{
int tmp = pCur->val;
pCur->val = pAfter->val;
pAfter->val = tmp;
}
pCur = pCur->pNext;
pAfter = pAfter->pNext;
}
}
}
代码测试
int main()
{
Node* pHead;
Init(&pHead);
for (int i=0;i<15;i++)
{
Insert(pHead, rand() % 100);
}
ListSort(pHead);
Show(pHead);
return 0;
}