六、排序
1.内部排序
1.1插入排序
1.1.1直接插入排序
下面的代码用了哨兵,也可以不用。
#include <iostream>
using namespace std;
void Show(int arr[], int n)
{
for (int i = 1; i <= n; i++)
{
cout << arr[i];
if (i < n)
cout << ' ';
}
cout << endl;
}
void Sort(int arr[], int n)
{
for (int i = 2; i <= n; i++) //从第二位开始遍历
{
if (arr[i] < arr[i - 1]) //当前位小于前一位证明需要进行插入排序
{
arr[0] = arr[i]; //将哨兵放在第0位
int j;
for (j = i; arr[0] < arr[j - 1]; j--)
arr[j] = arr[j - 1];
arr[j] = arr[0];
} //if
Show(arr, n);
} // for i
}
int main()
{
int n;
cin >> n;
int *arr = new int[n + 1]; //第0位用于放哨兵
for (int i = 1; i <= n; i++)
cin >> arr[i];
//Show(arr, n);
Sort(arr, n);
delete[] arr;
return 0;
}
/*
样例输入:
7 34 23 677 2 1 453 3
样例输出:
23 34 677 2 1 453 3
23 34 677 2 1 453 3
2 23 34 677 1 453 3
1 2 23 34 677 453 3
1 2 23 34 453 677 3
1 2 3 23 34 453 677
*/
1.1.2折半插入排序
利用了插入排序前半段序列有序的特点,使用折半查找进行插入
#include <iostream>
using namespace std;
void Show(int arr[], int n)
{
for (int i = 1; i <= n; i++)
{
cout << arr[i];
if (i < n)
cout << ' ';
}
cout << endl;
}
void Sort(int arr[], int n)
{
for (int i = 2; i <= n; i++) //从第二位开始遍历
{
if (arr[i] < arr[i - 1]) //当前位小于前一位证明需要进行插入排序
{
arr[0] = arr[i]; //将哨兵放在第0位
int low = 1, high = i - 1;
while (low <= high)
{
int mid = (low + high) / 2;
if (arr[0] < arr[mid])
high = mid - 1;
else
low = mid + 1;
}
//此时low=high+1
for (int j = i - 1; j >= high + 1; j--)
arr[j + 1] = arr[j];
//arr[high + 1] = arr[0];
arr[low] = arr[0];
} //if
Show(arr, n);
} // for i
}
int main()
{
int n;
cin >> n;
int *arr = new int[n + 1]; //第0位用于放哨兵
for (int i = 1; i <= n; i++)
cin >> arr[i];
//Show(arr, n);
Sort(arr, n);
delete[] arr;
return 0;
}
/*
样例输入:
7 34 23 677 2 1 453 3
样例输出:
23 34 677 2 1 453 3
23 34 677 2 1 453 3
2 23 34 677 1 453 3
1 2 23 34 677 453 3
1 2 23 34 453 677 3
1 2 3 23 34 453 677
*/
1.1.3希尔排序
给出一个数据序列,使用希尔排序算法进行降序排序。
间隔gap使用序列长度循环除2直到1
#include <iostream>
using namespace std;
void Show(int arr[], int n)
{
for (int i = 1; i <= n; i++)
{
cout << arr[i];
if (i < n)
cout << ' ';
}
cout << endl;
}
void Sort(int arr[], int n)
{
for (int gap = n / 2; gap >= 1; gap /= 2)
{
for (int i = gap + 1; i <= n; i++)
{
arr[0] = arr[i]; //放置进行需要插入的值
int j = i;
while (j - gap > 0)
{
if (arr[j - gap] < arr[0])
arr[j] = arr[j - gap];
else
break;
j -= gap;
}
arr[j] = arr[0];
} //for i
Show(arr, n);
} // for gap
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int *arr = new int[n + 1]; //第0位用于放置需要插入的值
for (int i = 1; i <= n; i++)
cin >> arr[i];
//Show(arr, n);
Sort(arr, n);
delete[] arr;
}
return 0;
}
/*
样例输入:
2
6
111 22 6 444 333 55
8
77 555 33 1 444 77 666 2222
样例输出:
444 333 55 111 22 6
444 333 111 55 22 6
444 555 666 2222 77 77 33 1
666 2222 444 555 77 77 33 1
2222 666 555 444 77 77 33 1
*/
1.2交换排序
1.2.1冒泡排序
下面的代码目的是输出冒泡排序的次数
#include <iostream>
using namespace std;
int Sort(int arr[], int n)
{
int cnt = 0;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
cnt++;
} // if
} //for j
} //for i
return cnt;
}
int main(int argc, char const *argv[])
{
int n;
while (cin >> n)
{
int *arr = new int[n];
for (int i = 0; i < n; i++)
cin >> arr[i];
cout << Sort(arr, n) << endl;
delete[] arr;
}
return 0;
}
1.2.2快速排序
下文快速排序代码还有优化的空间,比如说小数组可以改为插入排序,尾递归减少递归次数等。
#include <iostream>
using namespace std;
void PrintArray(int arr[], int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << ' ';
cout << endl;
}
//将数组切开,返回枢轴量的位置
int Partition(int arr[], int low, int high)
{
int pivot = arr[low];
while (low < high)
{
//原算法思想是进行枢轴量与其他值交换,但经过分析后可以使用赋值操作优化算法
//先移动high,从后往前找到比数轴量小的数,然后将小的值赋值到low的位置
while (low < high && arr[high] >= pivot)
high--;
arr[low] = arr[high]; //将小的值赋值到前面
//再移动low,从前往后找到比数轴量大的数,然后将大的值赋值到high的位置
while (low < high && arr[low] <= pivot)
low++;
arr[high] = arr[low]; //将大的值赋值到前面
}
arr[low] = pivot;
return low;
}
void QuickSort(int arr[], int low, int high, int n)
{
if (low >= high)
return;
int pivot = Partition(arr, low, high);
PrintArray(arr, n);
QuickSort(arr, low, pivot - 1, n);
QuickSort(arr, pivot + 1, high, n); //此处可以使用尾递归优化
}
int main(int argc, char const *argv[])
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int *arr = new int[n];
for (int i = 0; i < n; i++)
cin >> arr[i];
QuickSort(arr, 0, n - 1, n);
cout << endl;
delete[] arr;
}
return 0;
}
/*
样例输入:
2
6
111 22 6 444 333 55
8
77 555 33 1 444 77 666 2222
样例输出:
55 22 6 111 333 444
6 22 55 111 333 444
6 22 55 111 333 444
6 22 55 111 333 444
1 33 77 555 444 77 666 2222
1 33 77 555 444 77 666 2222
1 33 77 77 444 555 666 2222
1 33 77 77 444 555 666 2222
1 33 77 77 444 555 666 2222
*/
1.3选择排序
1.3.1简单选择排序
1.3.2堆排序
还有堆的插入没有写,堆的插入的主要思想就是向上调整树。
#include <iostream >
using namespace std;
void PrintArray(int arr[], int n)
{
cout << n << ' ';
for (int i = 1; i <= n; i++)
cout << arr[i] << ' ';
cout << endl;
}
void AdjustDown(int arr[], int n, int parent)
{
arr[0] = arr[parent]; //0位置存放需要调整的结点
for (int i = 2 * parent; i <= n; i *= 2)
{
if (i < n && arr[i] > arr[i + 1]) //判断左右孩子大小,取小的那个与双亲比较
i++;
if (arr[0] <= arr[i]) //如果双亲小于孩子,则不需要调整
break;
else //如果双亲比孩子大,将孩子赋值给双亲,然后继续向下寻找
{
arr[parent] = arr[i];
parent = i;
}
}
arr[parent] = arr[0]; //最后将原双亲赋值给最后的位置,完成交换
}
void BuildMinHeap(int arr[], int n) //建立小顶堆
{
//默认叶子节点都是符合小顶堆,所以从中间开始调整
for (int i = n / 2; i > 0; i--)
AdjustDown(arr, n, i);
}
void HeapSort(int arr[], int n)
{
BuildMinHeap(arr, n);
for (int i = n; i > 1; i--)
{
PrintArray(arr, n);
//将顶部的结点换到树的最末尾,再对树从1开始进行调整
swap(arr[i], arr[1]);
AdjustDown(arr, i - 1, 1);
}
}
int main(int argc, char const *argv[])
{
int n;
cin >> n;
int *arr = new int[n + 1];
for (int i = 1; i <= n; i++)
cin >> arr[i];
HeapSort(arr, n);
PrintArray(arr, n);
delete[] arr;
return 0;
}
/*
样例输入:
8 34 23 677 2 1 453 3 7
样例输出:
8 1 2 3 7 23 453 677 34
8 2 7 3 34 23 453 677 1
8 3 7 453 34 23 677 2 1
8 7 23 453 34 677 3 2 1
8 23 34 453 677 7 3 2 1
8 34 677 453 23 7 3 2 1
8 453 677 34 23 7 3 2 1
8 677 453 34 23 7 3 2 1
*/
1.4归并排序
1.4.1’2’-路归并排序
下面展示递归和迭代两种写法,不同的写法进行排序时候的顺序会有一定差异。
#include <iostream>
using namespace std;
int n; //数组长度
void PrintArray(string arr[])
{
for (int i = 1; i <= n; i++)
cout << arr[i] << ' ';
cout << endl;
}
void Merge(string arr[], int low, int mid, int high)
{
string *temp = new string[n + 1];
int i, j, k;
for (i = low; i <= high; i++) //现将传入的数组赋值给辅助数组
temp[i] = arr[i];
//i指向前一个数组的元素,j指向后一个数组的元素,k指向原数组的元素
for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++)
{
//比较前后两个数组对应的元素,将大的放入原数组
if (temp[i] > temp[j])
arr[k] = temp[i++];
else
arr[k] = temp[j++];
}
while (i <= mid) //如果前一个数组还未完全存入
arr[k++] = temp[i++];
while (j <= high) //如果后一个数组还未完全存入
arr[k++] = temp[j++];
delete[] temp;
}
void MergeSort(string arr[]) //迭代法
{
for (int step = 1; step < n; step *= 2) //比较的步长
{
//low放第一个数组的第一个元素的位置,mid放第一个数组最后一个元素的位置
//high放第二个数组的最后一个元素的位置
int low, mid, high;
for (low = 1; low + step <= n; low = high + 1)
{
mid = low + step - 1;
high = mid + step;
if (high > n)
high = n;
Merge(arr, low, mid, high);
} //不断取出符合步长的两个数组进行合并
PrintArray(arr);
} //不断增加步长
}
void MergeSort(string arr[], int low, int high) //递归法
{
if (low >= high)
return;
int mid = (low + high) / 2;
MergeSort(arr, low, mid);
MergeSort(arr, mid + 1, high);
Merge(arr, low, mid, high);
PrintArray(arr);
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> n;
string *arr = new string[n + 1];
for (int i = 1; i <= n; i++)
cin >> arr[i];
MergeSort(arr); //调用迭代法
//MergeSort(arr, 1, n); //调用递归法
cout << endl;
delete[] arr;
}
return 0;
}
/*
样例输入:
2
6 shenzhen beijing guangzhou futian nanshan baoan
10 apple pear peach grape cherry dew fig haw lemon marc
样例输出(迭代):
shenzhen beijing guangzhou futian nanshan baoan
shenzhen guangzhou futian beijing nanshan baoan
shenzhen nanshan guangzhou futian beijing baoan
pear apple peach grape dew cherry haw fig marc lemon
pear peach grape apple haw fig dew cherry marc lemon
pear peach haw grape fig dew cherry apple marc lemon
pear peach marc lemon haw grape fig dew cherry apple
-------------------------------------------------------
样例输出(递归):
shenzhen beijing guangzhou futian nanshan baoan
shenzhen guangzhou beijing futian nanshan baoan
shenzhen guangzhou beijing nanshan futian baoan
shenzhen guangzhou beijing nanshan futian baoan
shenzhen nanshan guangzhou futian beijing baoan
pear apple peach grape cherry dew fig haw lemon marc
pear peach apple grape cherry dew fig haw lemon marc
pear peach apple grape cherry dew fig haw lemon marc
pear peach grape cherry apple dew fig haw lemon marc
pear peach grape cherry apple fig dew haw lemon marc
pear peach grape cherry apple haw fig dew lemon marc
pear peach grape cherry apple haw fig dew marc lemon
pear peach grape cherry apple marc lemon haw fig dew
pear peach marc lemon haw grape fig dew cherry apple
*/
1.5基数排序
#include <iostream>
#include <queue>
using namespace std;
void PrintArray(int arr[], int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << ' ';
cout << endl;
}
void PrintQueue(queue<int> q)
{
if (q.empty())
{
cout << "NULL" << endl;
return;
}
while (!q.empty())
{
cout << "->" << q.front();
q.pop();
}
cout << "->^" << endl;
}
void Sort(int arr[], int n)
{
queue<int> q[10];
for (int t = 1; t <= 5; t++)
{
for (int i = 0; i < n; i++)
{
int wei = 10;
for (int j = 1; j < t; j++)
wei *= 10;
int num = arr[i] % wei / (wei / 10);
q[num].push(arr[i]);
}
if (q[0].size() == n)
return;
for (int i = 0; i < 10; i++)
{
cout << i << ':';
PrintQueue(q[i]);
}
for (int i = 0, j = 0; i < n; i++)
{
while (q[j].empty())
{
j++;
}
arr[i] = q[j].front();
q[j].pop();
}
PrintArray(arr, n);
}
}
int main(int argc, char const *argv[])
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int *arr = new int[n];
for (int i = 0; i < n; i++)
cin >> arr[i];
Sort(arr, n);
cout << endl;
delete[] arr;
}
return 0;
}
/*
样例输入:
2
10 278 109 63 930 589 184 505 269 8 83
6 57 0 93 19 18 99
样例输出:
0:->930->^
1:NULL
2:NULL
3:->63->83->^
4:->184->^
5:->505->^
6:NULL
7:NULL
8:->278->8->^
9:->109->589->269->^
930 63 83 184 505 278 8 109 589 269
0:->505->8->109->^
1:NULL
2:NULL
3:->930->^
4:NULL
5:NULL
6:->63->269->^
7:->278->^
8:->83->184->589->^
9:NULL
505 8 109 930 63 269 278 83 184 589
0:->8->63->83->^
1:->109->184->^
2:->269->278->^
3:NULL
4:NULL
5:->505->589->^
6:NULL
7:NULL
8:NULL
9:->930->^
8 63 83 109 184 269 278 505 589 930
0:->0->^
1:NULL
2:NULL
3:->93->^
4:NULL
5:NULL
6:NULL
7:->57->^
8:->18->^
9:->19->99->^
0 93 57 18 19 99
0:->0->^
1:->18->19->^
2:NULL
3:NULL
4:NULL
5:->57->^
6:NULL
7:NULL
8:NULL
9:->93->99->^
0 18 19 57 93 99
*/
2.外部排序
暂不更新
1323



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



