1 排序思想
依次比较相邻的两个记录的关键字,若两个记录是反序的(即前一个记录的关键字大于后前一个记录的关键字),则进行交换,直到没有反序的记录为止。
① 首先将L->R[1]与L->R[2]的关键字进行比较,若为反序(L->R[1]的关键字大于L->R[2]的关键字),则交换两个记录;然后比较L->R[2]与L->R[3]的关键字,依此类推,直到L->R[n-1]与L->R[n]的关键字比较后为止,称为一趟冒泡排序,L->R[n]为关键字最大的记录。
② 然后进行第二趟冒泡排序,对前n-1个记录进行同样的操作。
一般地,第i趟冒泡排序是对L->R[1 … n-i+1]中的记录进行的,因此,若待排序的记录有n个,则要经过n-1趟冒泡排序才能使所有的记录有序。
#define FALSE 0
#define TRUE 1
void Bubble_Sort(Sqlist *L)
{
int j ,k , flag ;
for (j=0; j<L->length; j++) /* 共有n-1趟排序 */
{
flag=TRUE ;
for (k=1; k<=L->length-j; k++) /* 一趟排序 */
if (LT(L->R[k+1].key, L->R[k].key ) )
{
flag=FALSE ;
L->R[0]=L->R[k] ;
L->R[k]=L->R[k+1] ;
L->R[k+1]=L->R[0] ;
}
if (flag==TRUE) break ;
}
}
故时间复杂度:T(n)=O(n²)
空间复杂度:S(n)=O(1)
快速排序
1 排序思想
通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,再分别对这两部分记录进行下一趟排序,以达到整个序列有序。
2 排序过程
设待排序的记录序列是R[s…t] ,在记录序列中任取一个记录(一般取R[s])作为参照(又称为基准或枢轴),以R[s].key为基准重新排列其余的所有记录,方法是:
◆ 所有关键字比基准小的放R[s]之前;
◆ 所有关键字比基准大的放R[s]之后。
以R[s].key最后所在位置i作为分界,将序列R[s…t]分割成两个子序列,称为一趟快速排序。
3 一趟快速排序方法
从序列的两端交替扫描各个记录,将关键字小于基准关键字的记录依次放置到序列的前边;而将关键字大于基准关键字的记录从序列的最后端起,依次放置到序列的后边,直到扫描完所有的记录。
设置指针low,high,初值为第1个和最后一个记录的位置。
设两个变量i,j,初始时令i=low,j=high,以R[low].key作为基准(将R[low]保存在R[0]中) 。
① 从j所指位置向前搜索:将R[0].key与R[j].key进行比较:
◆ 若R[0].key≤R[j].key :令j=j-1,然后继续进行比较, 直到i=j或R[0].key>R[j].key为止;
◆ 若R[0].key>R[j].key :R[j]ÞR[i],腾空R[j]的位置, 且令i=i+1;
② 从i所指位置起向后搜索:将R[0].key与R[i].key进行比较:
◆ 若R[0].key≥R[i].key :令i=i+1,然后继续进行比较, 直到i=j或R[0].key<R[i].key为止;
◆ 若R[0].key<R[i].key :R[i]ÞR[j],腾空R[i]的位置, 且令j=j-1;
① 重复①、②,直至i=j为止,i就是R[0](基准)所应放置的位置。
4 一趟排序示例
设有6个待排序的记录,关键字分别为29, 38, 22, 45, 23, 67,一趟快速排序的过程如图10-7所示。
⑴ 一趟快速排序算法的实现
int quick_one_pass(Sqlist *L , int low, int high)
{
int i=low, j=high ;
L->R[0]=L->R[i] ; /* R[0]作为临时单元和哨兵 */
do
{
while (LQ(L->R[0].key, L->R[j].key)&&(j>i))
j-- ;
if (j>i)
{
L->R[i]=L->R[j] ;
i++;
}
while (LQ(L->R[i].key, L->R[0].key)&&(j>i))
i++ ;
if (j>i)
{
L->R[j]=L->R[i] ;
j--;
}
} while(i!=j) ; /* i=j时退出扫描 */
L->R[i]=L->R[0] ;
return(i) ;
}
⑵ 快速排序算法实现
当进行一趟快速排序后,采用同样方法分别对两个子序列快速排序,直到子序列记录个为1为止。
① 递归算法
void quick_Sort(Sqlist *L , int low, int high)
{
int k ;
if (low<high)
{
k=quick_one_pass(L, low, high);
quick_Sort(L, low, k-1);
quick_Sort(L, k+1, high);
} /* 序列分为两部分后分别对每个子序列排序 */
}
② 非递归算法
# define MAX_STACK 100
void quick_Sort(Sqlist *L , int low, int high)
{
int k , stack[MAX_STACK] , top=0;
do
{
while (low<high)
{
k=quick_one_pass(L,low,high);
stack[++top]=high ;
stack[++top]=k+1 ;
/* 第二个子序列的上,下界分别入栈 */
high=k-1 ;
}
if (top!=0)
{
low=stack[top--] ;
high=stack[top--] ;
}
}while (top!=0&&low<high) ;
}
快速排序的平均时间复杂度是:T(n)=O(n㏒2n)
快速排序的空间复杂度是:S(n)=O(㏒2n)
从排序的稳定性来看,快速排序是不稳定的。