本文主要是介绍DataStructure-9-排序技术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
9.1 排序技术
9.1.1 概念
9.1.1 正序,逆序
若待排记录序列中的记录已按关键码排好序,称此记录序列为正序;若待排序序列中记录的排列顺序与排好序的顺序正好相反,称此记录序列为逆序(反序).
9.1.2 趟
在排序过程中,将待排序的记录序列扫描一遍称为一趟
9.1.4 排序算法的稳定性
9.1.5 排序的分类
9.1.6 排序算法的性能
插入排序
9.2 直接插入排序
9.2.1 基本思想:
依次将待排序序列中的每一个记录插入到一个已排好序的序列中,直到全部记录都排好序.
9.2.2 具体排序过程:
①将整个待排序的记录序列划分成有序区和无序区,初始时有序区为待排序序列中的第一个记录,
无序区包括所有剩余待排序的记录.
②将无序区的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录.
③重复执行②,直到无序区中没有记录为止.
9.2.3 伪代码:
1. 0号下标作为哨兵存在,从1号下标元素开始,该元素可以认为已经被排好序.
2. 从无序区中取出一个元素,直到取完为止.
3. 将其赋值给哨兵,此后直接使用哨兵进行比较.
4. 将哨兵与有序区中元素从后向前依次比较.
4.1若哨兵小于有序区元素,则有序区元素后移一位.
5. 直到哨兵大于或等于有序区元素的位置.将哨兵插入到该位置之后.
9.2.4 代码实现
/*直接插入排序(从小到大),0号单元作为暂存单元和监视哨*/
void InsertSort(int r[],int n)
{
int i,j;
/*重复下述过程,直到所有元素都排序完毕。
* 从下标为2的位置开始,下标为1的位置可以认为是已经排好序*/
for(i=2;i<=n;i++)
{
/*暂存新元素,设置哨兵*/
r[0] = r[i];
/*新元素与排好序的序列从后往前进行比较,
* 若新元素小于该元素,则循环,并将该元素后移一位*/
for(j=i-1;r[j]>r[0];j--)
{
r[j+1] = r[j];
}
/*新元素大于或等于该元素时,则将新元素插入到该元素后*/
r[j+1] = r[0];
}
}
9.2.5
稳定性: 稳定的排序方式.
时间复杂度: O(n^2) .
9.3 希尔排序
9.3.1 基本思想:
先将整个待排序记录序列分割成若干个子序列,在子序列内分别进行直接插入排序,
待整个序列基本有序时,再对全体记录进行一次直接插入排序.
9.3.2 具体排序过程:
假设待排序的记录为n个,先取整数d<n,例如,取d = n/2下取整,将所有相距为d的记录构成一组,从而将整个
待排序记录序列分割成为d个子序列.
对每个子序列分别进行直接插入排序,然后再缩小间隔d.例如,取d = d/2下取整,重复上述分割,再对每个子
序列分别进行直接插入排序,直到最后取d = 1,即将所有记录放在一组进行一次直接插入排序,最终将所有记录
重新排列成按关键码有序的序列.
9.3.3 伪代码
1. 取d = n/2作为增量,之后以d = d/2作为增量,把待排序列分成d个组.
2. 将所有距离为d的倍数的记录放在一个子序列中.
3. 将新记录与前d个位置的记录比较,若新纪录小于已排序子序列的记录
3.1 记录后移d个位置.
4. 当新纪录大于或等于已排序子序列的记录,将新纪录插入该位置.
9.3.4 代码实现
void ShellSort(int r[],int n)
{
int d,i,j;
/*以增量为d进行直接插入排序*/
for(d = n/2;d >= 1;d = d/2)
{
/*从子序列的第二个元素开始*/
for(i = d+1;i <= n;i++)
{
r[0] = r[i]; /*暂存待插记录*/
for(j=i-d;j>0&&r[j]>r[0];j=j-d)
{
r[j+d] = r[j]; /*记录后移d个位置*/
}
r[j+d] = r[0];
}
}
}
9.3.5
稳定性:不稳定排序算法
平均时间复杂度: 在O(nLog2ⁿ) ~O(n^2),在某个特定范围时,希尔排序的时间性能约为O(n^1.3) .
交换排序
9.4 冒泡排序
9.4.1 基本思想
两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止.
9.4.2 具体排序过程
① 将整个待排序的记录序列划分成有序区和无序区,初始时有序区为空,无序区包含所有待排序的记录.
② 对无序区从前向后依次将相邻记录的关键码进行比较,若反序则交换,从而使得关键码小的记录向前移,关键码大的向后移.
③ 重复执行②,直到无序区中没有反序的记录.
9.4.3 伪代码
1. 控制冒泡排序的趟数从1~n
1.1 执行一趟冒泡排序
1.1.1 如果当前值比后面的值大,则交换.
9.4.4 代码实现
/*从小到大排序*/
{
int i,j;
/*0号单元用作交换操作的暂存单元*/
/*控制冒泡排序的趟数从1~n*/
for(i=1;i<n;i++)
{
/*执行一趟排序*/
for(j=2;j<n;j++)
{
/*前面的值比后面的大时,交换*/
if(r[j-1]>r[j])
{
r[0]=r[j-1];
r[j-1]=r[j];
r[j]=r[0];
}
}
}
}
/*改进算法*/
void BubbleSort1(int r[],int n)
{
int i,j;
bool flag = true;
/*0号单元用作交换操作的暂存单元*/
for(i=1;i<n && flag==true;i++)
{
flag = false;
for(j=2;j<n;j++)
{
if(r[j-1]>r[j])
{
r[0]=r[j-1];
r[j-1]=r[j];
r[j]=r[0];
flag = true;
}
}
}
}
/*改进算法*/
void BubbleSort2(int r[],int n)
{
int j;
int exchange=n;
int bound;
/*0号单元用作交换操作的暂存单元*/
while(exchange != 0)
{
bound = exchange;
exchange = 0 ;
for(j=1;j<bound;j++)
{
if(r[j]>r[j+1])
{
r[0]=r[j];
r[j]=r[j+1];
r[j+1]=r[0];
exchange = j;
}
}
}
}
9.4.5
平均时间复杂度: O(n^2)
稳定性: 稳定的排序方法
9.5 快速排序
9.5.1 基本思想
首先选取一个轴值(povit,即比较的基准),将待排序记录分成独立的两部分,左侧记录的关键码均小于或等于轴值,
右侧的关键码均大于或等于轴值,然后分别对左右两部分重复执行上述过程,直到整个序列有序.
9.5.2 具体排序过程
① 从序列中选取一个记录作为轴值.
② 将比轴值大的数,放到轴值右边;将比轴值小的数,放到轴值的左边.
③ 再对左右分区重复步骤②,直到各分区只有一个数(即各分区的轴值).
9.5.3 伪代码(一次划分)
1. 将i和j分别指向待划分区间的最左侧记录和最右侧记录的位置.
2. 重复下述过程,直到 i = j
2.1 右侧扫描,直到记录 j 的关键码小于轴值记录的关键码
2.2 如果存在划分区间,则将 r[j] 与 r[i] 交换,并执行 i++
2.3 左侧扫描,直到记录 i 的关键码大于轴值记录的关键码
2.4 如果存在划分区间, 则将 r[i] 与 r[j] 交换,并执行 j--
3. 退出循环,说明 i 和 j指向了轴值记录的所在位置,返回该位置
9.5.4 代码实现
/*一次划分,0号单元作为交换操作的辅助单元*/
int Partition(int r[],int first,int end)
{
/*将i和j分别指向待划分区间的最左侧记录和最右侧记录的位置*/
int i = first,j = end;
/*重复执行下述操作,直到i=j*/
while(i<j)
{
/*右侧扫描,直到记录j的关键码小于轴值*/
while(i<j && r[i]<=r[j])
{
j--;
}
/*若存在划分区间,则将r[j] 与 r[i]交换,并执行 i++*/
if(i<j)
{
r[0] = r[i];
r[i] = r[j];
r[j] = r[0];
i++;
}
/*左侧扫描,直到记录j的关键码大于轴值*/
while(i<j && r[i]<=r[j])
{
i++;
}
/*若存在划分区间,则将r[i] 与 r[j]交换,并执行j--*/
if(i<j)
{
r[0] = r[i];
r[i] = r[j];
r[j] = r[0];
j--;
}
}
/*推出循环,说明i和j指向了轴值所在位置,返回该位置*/
return i;
}
void QuickSort(int r[],int first,int end)
{
int povit;
/*区间长度大于1,执行依次划分,否则递归结束*/
if(first < end)
{
/*一次划分*/
povit = Partition(r,first,end);
/*递归对左测区间进行快速排序*/
QuickSort(r,first,povit-1);
/*递归对右侧区间进行快速排序*/
QuickSort(r,povit+1,end);
}
}
//方法一:
/*快速排序非递归算法*/
void QuickSort1(int *data, int first, int end)
{if (data == NULL || first < 0 || end < 0){return;}int pivot;int pp;stack<int> stack;int pEnd = end; //记录最后元素位置//cout << "stack:" << stack.empty() << endl;stack.push(end);while (first < end || !stack.empty()){while (first < end){pivot = Partition(data, first, end);stack.push(pivot);end = pivot - 1;}if (!stack.empty()){pivot = stack.top();stack.pop();//当划分到前半部分(即还没有用到最后值的时候),//此时first,end分别取栈顶两个元素之间的最小和最大值if (pivot != pEnd && stack.top() != pEnd){first = pivot + 1;end = stack.top() - 1;}//当划分到后半部分包含end时,//此时让first=pivot+1, end = pEnd.目的是为了将最后元素也加入划分中else if (pivot != pEnd && stack.top() == pEnd){first = pivot + 1;end = pEnd;}//当栈顶为end时,说明排序已经结束else if (pivot == pEnd){first = end;}}}
}
//方法二:
void QuickSort2(int *data, int first, int end)
{
if (data == NULL || first < 0 || end < 0)
{
return;
}
int pivot;
stack<int> stack;
pivot = Partition(data, first, end);
if (first < pivot - 1)
{
stack.push(first);
stack.push(pivot - 1);
}
if (end > pivot + 1)
{
stack.push(pivot + 1);
stack.push(end);
}
while (!stack.empty())
{
int j = stack.top(); //获取结尾下标
stack.pop();
int i = stack.top(); //获取开始下标
stack.pop();
//进行划分
pivot = Partition(data, i, j);
if (i < pivot - 1)
{
stack.push(i);
stack.push(pivot - 1);
}
if (j > pivot + 1)
{
stack.push(pivot + 1);
stack.push(j);
}
}
}
9.5.5
平均时间复杂度: O(nLog2ⁿ)
稳定性: 不稳定排序算法
选择排序
9.6 简单选择排序
9.6.1 基本思想
第i趟排序在待排序序列 r[i]~r[j](1 <= i<=n-1)中选取关键码最小的记录,
并和第i个记录交换作为有序序列的第i个记录.
9.6.2 具体实现过程
① 将整个记录序列划分成为有序区和无序区,初始时有序区为空,无序区含有待排序的所有记录 .
② 在无序区中选取关键码最小的记录,将它与无序区中的第一个记录交换,使得有序区增加一条记录,无序区减少一条记录
③ 不断重复执行②,直到无序区只剩下一条记录为止.此时所有记录已经按关键码从小到大的顺序排列.
9.6.3 伪代码
1. 对n个记录进行n-1趟简单选择排序,从i =1开始
2. index 记录最小值的下标位置
3. 从i+1位置开始在无序区中选择最小值
3.1 若r[j] < r[index] ,则index = j
4. 最小记录选择完毕,若index != i,则交换i与index位置的记录
9.6.4 代码实现
/*简单选择排序,0号单元用作交换操作的暂存单元*/
void SelectSort(int r[],int n)
{
int i,j,index;
/*对n个记录进行n-1趟简单选择排序(由于简单选择排序到第n-1次后,
* 无序区中只剩下一个值,且是最大值,因此只需要进行n-1趟排序)*/
for(i=1;i<n;i++)
{
/*index 记录最小值*/
index = i;
/*第i位置元素与后面i+1到n的元素进行比较*/
for(j=i+1;j<=n;j++)
{
/*若存在更小的记录,则index记录其位置*/
if(r[j] < r[index])
{
index = j;
}
}
/*如果index不是i位置,则说明找到更小的值*/
if(index != i)
{
/*交换*/
r[0] = r[i];
r[i] = r[index];
r[index] = r[0];
}
}
}
9.6.5
时间复杂度: O(n^2)
稳定性: 不稳定的排序方法
9.7 堆排序
9.7.1 堆的定义
堆是具有下列性质的完全二叉树(完全二叉树是描述堆的工具):每个节点的值都小于或等于其左右孩子的值(称为小根堆);
或者每个结点的值都大于或等于其左右孩子的值(大根堆).
9.7.2 筛选算法伪代码
1. 设置i和j,分别指向当前要筛选的结点和要筛选节点的左孩子;
2. 若节点i已经是叶子,则筛选完毕,算法结束;否则,执行下述操作:
2.1 将 j 指向节点 i 的左右孩子中较大者;
2.2 如果 r[i] > r[j] , 则筛选完毕,算法结束;
2.3 如果 r[i] < r[j] ,则将r[i]与r[j]交换; 令 i = j,转步骤2继续筛选;
9.7.3 代码实现
/*堆筛选算法,0号单元用作交换操作的暂存单元*/
void Sift(int r[],int k,int m)
{
/*i指向被筛选结点,j指向结点i的左孩子*/
int i = k,j = 2*i;
/*筛选还没进行到左孩子*/
while(j <= m)
{
/*比较i的左右孩子,j指向较大者*/
if(j<m && r[j]<r[j+1]) //(2i+1)<=m,则i的右孩子为2i+1
{
j++;
}
/*如果r[i]>r[j],则筛选完毕,算法结束*/
if(r[i]>r[j])
{
break;
}
/*否则,即r[i]<r[j],则将r[i]与r[j]交换*/
else{
r[0] = r[i];
r[i] = r[j];
r[j] = r[0];
i=j; //被筛选结点位于原来结点j的位置
j=2*i;
}
}
}
9.7.4 堆排序基本思想(大根堆):
① 首先将待排序的记录序列构造成一个堆(大根堆),此时,选出堆中所有记录的最大者(即堆顶记录).
② 然后将堆顶记录移走,并将剩余的记录再调成堆,这样就找出了次大的记录.
③ 重复执行步骤②,直到堆中只有一个记录为止.
9.7.5 伪代码
1. 初始建堆,从最后一个分支节点到根结点(即从n/2到1位置的结点)
2. 重复执行移走堆顶记录及重建堆的操作
9.7.6 代码实现
/*堆排序算法,0号单元用作交换操作的暂存单元*/
void HeapSort(int r[],int n)
{
int i;
/*初始建堆,从最后一个分支结点到根结点*/
for(i = n/2;i>=1;i--)
{
Sift(r,i,n);
}
/*重复执行移去堆顶结点及重建堆的操作*/
for(i = 1;i<n;i++)
{
/*将堆顶记录移动到数组后方有序区中*/
r[0] = r[1];
r[1] = r[n-i+1];
r[n-i+1] = r[0];
/*重建堆*/
Sift(r,1,n-i);
}
}
9.7.7
平均时间复杂度:O(nLog2ⁿ)
稳定性: 不稳定的排序方法
9.8 归并排序
9.8.1 归并排序基本思想
将若干有序序列逐步归并,最终归并为一个有序序列
9.8.2 二路归并排序基本思想
将若干有序序列进行两两归并,直至所有待排序记录都在一个有序序列位置.
9.8.3 具体排序过程
① 将具有n个待排序的记录序列看成是n个长度为1的有序序列
② 进行两两归并,得到n/2(上取整) 个长度为2(最后一个有序序列的长度可能是1)的有序序列
③ 再进行两两归并,得到 n/4(上取整) 个长度为4(最后一个有序序列的长度可能小于4)的有序序列
④ 直至得到一个长度为n的有序序列
9.8.4 代码实现
/*对两个有序序列r[s]~r[m]和r[m+1]~r[t]进行一次归并排序*/
void Merge(int r[],int r1[],int s,int m,int t)
{
/*i指向第一个有序序列的第一个记录,
* j指向第二个有序序列的第一个记录*/
int i=s,j=m+1,k=s;
/*当i<m并且j<t,执行下述操作*/
while(i<=m && j<=t)
{
/*取r[i]和r[j]中较小者放入r1[k]中,
* 并各自指向下一条记录*/
if(r[i]<=r[j])
{
r1[k++]=r[i++];
}else{
r1[k++]=r[j++];
}
}
/*若第一个子序列没有处理完,则进行收尾处理*/
if(i<=m)
{
while(i<=m)
{
r1[k++] = r[i++];
}
}
/*若第二个子序列没有处理完,则进行收尾处理*/
else{
while(j<=t)
{
r1[k++] = r[j++];
}
}
}
/*一趟归并排序,分为三种情况:
* 1. 若i<= n-2h+1,则表示待归并的两个相邻有序序列的长度均为h,
* 执行依一次归并,完成后i加2h,准备下一次归并。
* 2. 若i< n-h+1,则表明仍有两个现邻有序序列,一个长度为h,另一个长度小于h,
* 执行这两个有序序列的归并,完成后退出一趟归并。
* 3. 若i>= n-h+1,则表明只剩下一个有序序列,直接将该序列送到r1的相应位置,
* 完成后退出一趟归并*/
void MergePass(int r[],int r1[],int n,int h)
{
int i=1;
int k;
/*情况1:待归并记录至少有两个长度为h的子序列*/
while(i<= n-2*h+1)
{
Merge(r,r1,i,i+h-1,i+2*h-1);
i=i+2*h;
}
/*情况2:待归并记录中还有两个子序列,且有一个长度小于h*/
if(i<n-h+1)
{
Merge(r,r1,i,i+h-1,n);
}
/*情况3:待归并记录中只剩下一个子序列*/
else{
for(k=i;k<=n;k++)
{
r1[k] = r[k];
}
}
}
/*归并排序非递归排序,从下标1开始存放待排序序列。
* 开始时,有序序列的长度为1,结束时,有序序列的长度为n。
* 因此,可以用有序序列的长度来控制排序过程的结束。
* 另外,如果排序趟数为奇数,则最终结果在辅助数组r1中,应传回到数组r中*/
void MergeSort1(int r[],int r1[],int n)
{
/*初始时,子序列长度为1*/
int h=1;
while(h<n)
{
/*待排序序列从数组r中传到r1中*/
MergePass(r,r1,n,h);
h = 2*h;
/*待排序序列从数组r1中传到r中*/
MergePass(r1,r,n,h);
h = 2*h;
}
}
/*归并排序递归算法*/
void MergeSort2(int r[],int r1[],int s,int t)
{
int m;
/*待排序序列只有一个记录,递归结束*/
if(s == t)
{
r1[s] = r[s];
}else{
m = (s+t)/2;
MergeSort2(r,r1,s,m); /*归并排序前半个子序列*/
MergeSort2(r,r1,m+1,t); /*归并排序后半个子序列*/
Merge(r1,r,s,m,t); /*将已排好序的子序列归并*/
}
}
9.8.5
平均时间复杂度: O(nLog2ⁿ)
稳定性:稳定的排序算法
分配排序
9.9 桶式排序
9.9.1 基本思想
假设待排序记录的值都在 0 ~ m-1之间,设置m个桶, 首先将值为i的记录分配到第i个桶中,
然后再将各个桶中的记录依次收集起来.
9.9.2 具体实现过程
①分配操作:将记录插入到相应的队列中,入队在静态链表上实现,并修改相应的队头指针和队尾指针
②收集操作:将所有队列首尾相接
9.9.3 代码实现
/*分配排序*/
/*分配算法,first为静态链表的头指针,从下标0开始存放待排序序列*/
void Distribute(Node r[],int n,QueueNode q[],int m,int first)
{
int k;
int i = first;
/*依次分配每一个待排序记录*/
while(r[i].next != -1)
{
k=r[i].key;
/*如果队列为空,则直接将下标i放入到对应的队列中*/
if(q[k].front == -1)
{
q[k].front = i;
}
/*如果队列不为空,则在静态链表中实现插在队列尾部*/
else{
r[q[k].rear].next = i;
}
q[k].rear = i; //修改队尾指针
i=r[i].next; //i后移,处理下一个记录
}
q[k].rear = i; //修改队尾指针
i=r[i].next; //i后移,处理下一个记录
}
}
/*收集算法,将所有队列首尾相接*/
int Collect(Node r[],int n,QueueNode q[],int m,int first)
{
int last; //用于记录静态链表的尾标志
int k = 0;
/*找到第一个非空队列*/
while(q[k].front != -1)
{
k++;
}
first = q[k].front; //first为第一个记录
//printf("fffffff:%d\n",first);
last = q[k].rear; //设置last为队列k的最后一个记录
while(k<m)
{
k++;
if(q[k].front != -1) //第k个对了非空
{
/*将队列k的队头和前一个队列的队尾相接*/
r[last].next = q[k].front;
/*last为当前收集后的最后一个记录*/
last = q[k].rear;
}
}
r[last].next = -1; //在静态链表中设置尾标志
return first;
}
void BucketSort(Node r[],int n,int m)
{
int i,first;
QueueNode q[m];
/*初始化静态链表*/
for(i=0;i<n;i++)
{
r[i].next = i+1;
}
/*设置尾标志和头指针*/
r[n-1].next = -1;
first = 0;
/*初始化m个静态队列的队头和队尾指针*/
for(i=0;i<m;i++)
{
q[i].front = q[i].rear = -1;
}
//进行分配
Distribute(r,n,q,m,first);
//进行收集,first指向的静态链表有序
first = Collect(r,n,q,m,first);
//打印输出
Print2(r,n,first);
}
void Print2(Node r[],int n,int first)
{
while(r[first].next != -1)
{
printf("%d\n",r[first].key);
first = r[first].next;
}
}
9.9.4
平均时间复杂度:O(n+m)
稳定性:稳定的排序算法
9.10 基数排序
多关键码排序的两种基本情况:
①最主位优先MSD(most significant digit first)
先按最主位关键码k0进行排序,然后将序列分割成若干子序列,每个子序列中的记录具有相同的k0值,
在分别对每个子序列按关键码k1进行排序,然后将子序列分割成若干个更小的子序列,每个更小的子序列
中的记录具有相同的k1值.以此类推,直至按最次位关键码kd排序,最后将所有子序列收集在一起得到一个有
序序列.
②最次位优先LSD(least significant digit first)
从最次位关键码kd起进行排序,然后再按关键码次kd-1排序,依次重复,直至对最主关键码k0进行排序,
得到一个有序序列. LSD方法无须分割序列但要求按关键码kd-1 ~ k进行排序时采用稳定的排序方法.
9.10.1 基本思想
将关键码看成由若干个子关键码复合而成,然后借助分配和收集操作采用LSD方法进行排序
9.10.2 具体过程
① 第一趟排序按最次位关键码kd-1将具有相同码值的记录分配到一个队列中,然后再一次收集起来,
得到一个按关键码kd-1有序的序列
② 一般情况,第i趟排序按关键码kd-i将具有相同码值的记录分配到一个队列中,然后在依次收集起来,
得到一个按关键码kd-i有序的序列
9.10.3 代码实现
/*分配排序*/
/*分配算法,first为静态链表的头指针,从下标0开始存放待排序序列*/
void Distribute(Node r[],int n,QueueNode q[],int m,int first,int j)
{
int k;
int i = first;
/*依次分配每一个待排序记录*/
while(r[i].next != -1)
{
k=r[i].key[j];
/*如果队列为空,则直接将下标i放入到对应的队列中*/
if(q[k].front == -1)
{
q[k].front = i;
}
/*如果队列不为空,则在静态链表中实现插在队列尾部*/
else{
r[q[k].rear].next = i;
}
q[k].rear = i; //修改队尾指针
i=r[i].next; //i后移,处理下一个记录
}
q[k].rear = i; //修改队尾指针
i=r[i].next; //i后移,处理下一个记录
}
}
/*收集算法,将所有队列首尾相接*/
int Collect(Node r[],int n,QueueNode q[],int m,int first)
{
int last; //用于记录静态链表的尾标志
int k = 0;
/*找到第一个非空队列*/
while(q[k].front != -1)
{
k++;
}
first = q[k].front; //first为第一个记录
//printf("fffffff:%d\n",first);
last = q[k].rear; //设置last为队列k的最后一个记录
while(k<m)
{
k++;
if(q[k].front != -1) //第k个对了非空
{
/*将队列k的队头和前一个队列的队尾相接*/
r[last].next = q[k].front;
/*last为当前收集后的最后一个记录*/
last = q[k].rear;
}
}
r[last].next = -1; //在静态链表中设置尾标志
return first;
}
void BucketSort(Node r[],int n,int m,int d)
{
int i,j,first;
QueueNode q[m];
/*初始化静态链表*/
for(i=0;i<n;i++)
{
r[i].next = i+1;
}
/*设置尾标志和头指针*/
r[n-1].next = -1;
first = 0;
/*初始化m个静态队列的队头和队尾指针*/
for(i=0;i<m;i++)
{
q[i].front = q[i].rear = -1;
}
for(j=0;j<d;j++)
{
//进行分配
Distribute(r,n,q,m,first);
//进行收集,first指向的静态链表有序
first = Collect(r,n,q,m,first);
}
//打印输出
Print2(r,n,first);
}
{
while(r[first].next != -1)
{
printf("%d\n",r[first].key);
first = r[first].next;
}
}
9.10.4
平均时间复杂度:O(d(n+m))
稳定性:稳定的排序算法
这篇关于DataStructure-9-排序技术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!