冒泡排序思想
冒泡排序是一种交换排序,排序过程中两两比较相邻的元素大小,发生逆序则交换,直到没有逆序的元素的为止,每一轮的交换会将的高优先级元素移动到末尾作为已排好序的元素
算法步骤
以实现普通数组从小到大排序为例,对于一个给定的元素序列,每次从第一个元素开始依次遍历,两两比较逆序则交换:
- 第1轮遍历,第1个元素与第2个元素比较,逆序则交换,然后继续用第2个元素与第3个元素比较,直到第N-1个元素与第N个元素比较,比较了N-1次确定了最大元素;
- 第2轮遍历,同样第1个元素与第2个元素比较,第2个与第3个比较,直到第N-1和第N-2个元素比较,比较了N-2次确定了次大的元素;
- 第N-2轮遍历,比较第1个元素和第2个元素,第2个和第3个,比较了2次确定次大元素;
- 第N-1轮遍历,比较第1个元素和第2个元素,比较了1次确定最小元素,排序结束
以下图给定的序列为例,各轮排序结果如下:
算法复杂度
最理想情况:待排序元素已经有序,还是需要比较,但不需要数据交换;
最糟糕情况:待排序元素是逆序的情况下,需要每次比较,而且还要交换数据;
最坏的比较次数,与最坏的交换次数一样都是: ∑ i = 1 n − 1 i = 1 + 2 + 3 + . . . + ( n − 1 ) = n ( n − 1 ) 2 \sum_{i=1}^{n-1} i= 1+2+3+...+(n-1) = \frac{n(n-1)}{2} i=1∑n−1i=1+2+3+...+(n−1)=2n(n−1)
因此总的时间复杂度为O( n 2 n^2 n2)
数组冒泡排序源码
#include <stdio.h>
#include <stdlib.h>
//数组冒泡排序
void bubbleSort(int arr[], int sz)
{
int dumy;
//changed用于检测,当序列已经有序时直接跳出循环
int changed = 1;
for (int i = sz - 1; i >= 0 && changed == 1; i--)
{
int j = 0;
changed = 0;
for (int j = 1; j <= i; j++)
{
if (arr[j - 1] > arr[j])
{
dumy = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = dumy;
changed = 1;
}
}
}
}
int output(int arr[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d, ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {6,3,7,4,2,8,5};
// int arr[] = {2, 5, 6, 7, 1, 4, 8, 9};
// int arr[] = {1};
int n = sizeof(arr) / sizeof(int);
bubbleSort(arr, n);
output(arr, n);
return 0;
}
/*
2, 3, 4, 5, 6, 7, 8,
*/
数组存储结构的链表—冒泡排序
采用的也是两两比较,逆序的交换的方法,只是交换的方式有两种方法:
第1种:元素两两比较,交换时不改变指针域,而是直接交换数据域,时间该办法比较方便直接
第2种:交换时数据域不改动,而是通过修改指针域指向来实现数据逻辑顺序的交换,该方法交换时需要记录两个相邻元素各自的前驱指针和后继指针;
例如:需要交换指针B
和指针F
所指元素,且B
的前驱节点的指针为A
,F
的前驱节点的指针为E
,此时不仅要交换指针B
与指针F
,还需要交换其前驱指针A
与指针E
该方法实现对元素的1次交换通过对指针域作2次交换来实现,该方法复杂
以上两种方式,时间复杂度均为O( n 2 n^2 n2),以下以第1种方法为例说明:
数据存储结构的链表—冒泡排序源码
#include <stdio.h>
#include <stdlib.h>
struct Element
{
//数据域
int data;
//指针
int link;
};
//封装Element相关属性
struct StaticList
{
int maxSize;
// elements[0]为附加头节点
struct Element *elements;
// tail指针指向最后一个添加的元素,方便尾部插入
int tail;
// avail指针指向备用链表的第一个位置
int avail;
// 指示当前元素的个数
int currentSize;
};
//初始化一个基于数据的链表
int initStaticList(struct StaticList *p, int maxSize)
{
p->avail = 1;
p->tail = 0;
p->currentSize = 0;
p->maxSize = maxSize > 10 ? (maxSize + 1) : 10;
p->elements = (struct Element *)malloc(p->maxSize * sizeof(struct Element));
for (int i = 1; i < p->maxSize; i++)
{
p->elements[i].link = i + 1;
}
p->elements[0].link = -1;
p->elements[maxSize].link = -1;
}
void addElement(struct StaticList *p, int x)
{
int cur = p->avail;
if (cur == -1)
{
printf("memory overflow\n");
return;
}
p->avail = p->elements[cur].link;
p->elements[cur].data = x;
//新插入元素指针域为-1
p->elements[cur].link = -1;
p->elements[p->tail].link = cur;
p->tail = cur;
p->currentSize++;
}
void output(struct Element *ems)
{
int cur = ems[0].link;
while (cur != -1)
{
printf("%d, ", ems[cur].data);
cur = ems[cur].link;
}
printf("\n");
}
//冒泡排序
void bubbleSortElement(struct Element *ems){
int pos;
int posnext;
int endpos = -1;
int dumy;
//changed用于检查序列是否发生交换,若没有交换可结束多余的循环
int changed = 1;
//head指向第一个有效的元素
int first = ems[0].link;
while(endpos!=first && changed==1 ){
pos = first;
changed = 0;
//pos指向当前元素,posnext指向下一个元素
while(pos!= -1 && ems[pos].link!=endpos){
posnext = ems[pos].link;
//发生逆序则交换ems[pos].data与ems[posnext].data
if(ems[pos].data>ems[posnext].data){
dumy = ems[pos].data;
ems[pos].data = ems[posnext].data;
ems[posnext].data = dumy;
changed = 1;
}
pos = posnext;
}
//endpos标记结尾指针,每次更新
endpos = pos;
}
}
int main()
{
struct StaticList p;
int arr[] = {1, 4, 6, 7, 0, 3, 10, 9, 2, 9,
3, 7, 4, 8, 5, 6, 1, 0, 9999, 44,
9999, 2, 4, 9, 4, 12, 44, 99, -1, 0,
5, 888, 345, 12344, 5555, 9090, 10000, 123, 444, -888,
100, 400, 120000, 899999, -1, -2, 8, 9, 8};
// int arr[]={6,4,3,8,7,5,2,1};
// int arr[] = {2, 5, 6, 7, 1, 4, 8, 9};
// int arr[] = {1};
int n = sizeof(arr) / sizeof(int);
initStaticList(&p, n);
for (int i = 0; i < n; i++)
{
addElement(&p, arr[i]);
}
printf("#### bubble sort before ####\n");
output(p.elements);
printf("#### bubble sort after ####\n");
bubbleSortElement(p.elements);
output(p.elements);
free(p.elements);
return 0;
}