標題: C語言排序算法詳解 [打印本頁]
作者: 17079424323 時間: 2018-10-11 14:57
標題: C語言排序算法詳解
對排序做了一些詳細的介紹,需要的可以看看。
簡介
其中排序算法總結如下:
1.交換排序 交換排序的基本思想都為通過比較兩個數的大小,當滿足某些條件時對它進行交換從而達到排序的目的。
1.1冒泡排序基本思想:比較相鄰的兩個數,如果前者比后者大,則進行交換。每一輪排序結束,選出一個未排序中最大的數放到數組后面。
代碼:
#include<stdio.h>
//冒泡排序算法
void bubbleSort(int *arr, int n) {
for (int i = 0; i<n - 1; i++)
for (int j = 0; j < n - i - 1; j++)
{
//如果前面的數比后面大,進行交換
if (arr[j] > arr[j + 1]) {
int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;
}
}
}
int main() {
int arr[] = { 10,6,5,2,3,8,7,4,9,1 };
int n = sizeof(arr) / sizeof(int);
bubbleSort(arr, n);
printf("排序后的數組為:\n");
for (int j = 0; j<n; j++)
printf("%d ", arr[j]);
printf("\n");
return 0;
分析:
最差時間復雜度為O(n^2),平均時間復雜度為O(n^2)。穩定性:穩定。輔助空間O(1)。
升級版冒泡排序法:通過從低到高選出最大的數放到后面,再從高到低選出最小的數放到前面,如此反復,直到左邊界和右邊界重合。當數組中有已排序好的數時,這種排序比傳統冒泡排序性能稍好。
代碼:
#include<stdio.h>
//升級版冒泡排序算法
void bubbleSort_1(int *arr, int n) {
//設置數組左右邊界
int left = 0, right = n - 1;
//當左右邊界未重合時,進行排序
while (left<right) {
//從左到右遍歷選出最大的數放到數組右邊
for (int i =left; i < right; i++)
{
if (arr[ i] > arr[i + 1])
{
int temp = arr[ i]; arr[ i] = arr[i + 1]; arr[i + 1] = temp;
}
}
right--;
//從右到左遍歷選出最小的數放到數組左邊
for (int j = right;j> left; j--)
{
if (arr[j + 1] < arr[j])
{
int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;
}
}
left++;
}
}
int main() {
int arr[] = { 10,6,5,2,3,8,7,4,9,1 };
int n = sizeof(arr) / sizeof(int);
bubbleSort_1(arr, n);
printf("排序后的數組為:\n");
for (int j = 0; j<n; j++)
printf("%d ", arr[j]);
printf("\n");
return 0;
}
1.2. 快速排序 基本思想:選取一個基準元素,通常為數組最后一個元素(或者第一個元素)。從前向后遍歷數組,當遇到小于基準元素的元素時,把它和左邊第一個大于基準元素的元素進行交換。在利用分治策略從已經分好的兩組中分別進行以上步驟,直到排序完成。下圖表示了這個過程。
代碼:
#include<stdio.h>
void swap(int *x, int *y) {
int tmp = *x;
*x = *y;
*y = tmp;
}
//分治法把數組分成兩份
int patition(int *a, int left,int right) {
int j = left; //用來遍歷數組
int i = j - 1; //用來指向小于基準元素的位置
int key = a[right]; //基準元素
//從左到右遍歷數組,把小于等于基準元素的放到左邊,大于基準元素的放到右邊
for (; j < right; ++j) {
if (a[j] <= key)
swap(&a[j], &a[++i]);
}
//把基準元素放到中間
swap(&a[right], &a[++i]);
//返回數組中間位置
return i;
}
//快速排序
void quickSort(int *a,int left,int right) {
if (left>=right)
return;
int mid = patition(a,left,right);
quickSort(a, left, mid - 1);
quickSort(a, mid + 1, right);
}
int main() {
int a[] = { 10,6,5,7,12,8,1,3,11,4,2,9,16,13,15,14 };
int n = sizeof(a) / sizeof(int);
quickSort(a, 0,n-1);
printf("排序好的數組為:");
for (int l = 0; l < n; l++) {
printf("%d ", a[l]);
}
printf("\n");
return 0;
}
分析:
最差時間復雜度:每次選取的基準元素都為最大(或最小元素)導致每次只劃分了一個分區,需要進行n-1次劃分才能結束遞歸,故復雜度為O(n^2);最優時間復雜度:每次選取的基準元素都是中位數,每次都劃分出兩個分區,需要進行logn次遞歸,故時間復雜度為O(nlogn);平均時間復雜度:O(nlogn)。穩定性:不穩定的。輔助空間:O(nlogn)。
當數組元素基本有序時,快速排序將沒有任何優勢,基本退化為冒泡排序,可在選取基準元素時選取中間值進行優化。
2. 插入排序
2.1 直接插入排序基本思想:和交換排序不同的是它不用進行交換操作,而是用一個臨時變量存儲當前值。當前面的元素比后面大時,先把后面的元素存入臨時變量,前面元素的值放到后面元素位置,再到最后把其值插入到合適的數組位置。
代碼:
#include<stdio.h>
void InsertSort(int *a, int n) {
int tmp = 0;
for (int i = 1; i < n; i++) {
int j = i - 1;
if (a[ i] < a[j]) {
tmp = a[ i];
a[ i] = a[j];
while (tmp < a[j-1]) {
a[j] = a[j-1];
j--;
}
a[j] = tmp;
}
}
}
int main() {
int a[] = { 11,7,9,22,10,18,4,43,5,1,32};
int n = sizeof(a)/sizeof(int);
InsertSort(a, n);
printf("排序好的數組為:");
for (int i = 0; i < n; i++) {
printf(" %d", a[ i]);
}
printf("\n");
return 0;
}
分析:
最壞時間復雜度為數組為逆序時,為O(n^2)。最優時間復雜度為數組正序時,為O(n)。平均時間復雜度為O(n^2)。輔助空間O(1)。穩定性:穩定。
2.2 希爾(shell)排序 基本思想為在直接插入排序的思想下設置一個最小增量dk,剛開始dk設置為n/2。進行插入排序,隨后再讓dk=dk/2,再進行插入排序,直到dk為1時完成最后一次插入排序,此時數組完成排序。
代碼:
#include<stdio.h>
// 進行插入排序
// 初始時從dk開始增長,每次比較步長為dk
void Insrtsort(int *a, int n,int dk) {
for (int i = dk; i < n; ++i) {
int j = i - dk;
if (a[ i] < a[j]) { // 比較前后數字大小
int tmp = a[ i]; // 作為臨時存儲
a[ i] = a[j];
while (a[j] > tmp) { // 尋找tmp的插入位置
a[j+dk] = a[j];
j -= dk;
}
a[j+dk] = tmp; // 插入tmp
}
}
}
void ShellSort(int *a, int n) {
int dk = n / 2; // 設置初始dk
while (dk >= 1) {
Insrtsort(a, n, dk);
dk /= 2;
}
}
int main() {
int a[] = { 5,12,35,42,11,2,9,41,26,18,4 };
int n = sizeof(a) / sizeof(int);
ShellSort(a, n);
printf("排序好的數組為:");
for (int j = 0; j < n; j++) {
printf("%d ", a [j]);
}
return 0;
}
分析:
最壞時間復雜度為O(n^2);最優時間復雜度為O(n);平均時間復雜度為O(n^1.3)。輔助空間O(1)。穩定性:不穩定。希爾排序的時間復雜度與選取的增量有關,選取合適的增量可減少時間復雜度。
3. 選擇排序
3.1.直接選擇排序基本思想:依次選出數組最小的數放到數組的前面。首先從數組的第二個元素開始往后遍歷,找出最小的數放到第一個位置。再從剩下數組中找出最小的數放到第二個位置。以此類推,直到數組有序。
代碼:
#include<stdio.h>
void SelectSort(int *a, int n) {
for (int i = 0; i < n; i++)
{
int key = i; // 臨時變量用于存放數組最小值的位置
for (int j = i + 1; j < n; j++) {
if (a[j] < a[key]) {
key = j; // 記錄數組最小值位置
}
}
if (key != i)
{
int tmp = a[key]; a[key] = a[ i]; a[ i] = tmp; // 交換最小值
}
}
}
int main() {
int a[] = { 12,4,15,2,6,22,8,10,1,33,45,24,7 };
int n = sizeof(a) / sizeof(int);
SelectSort(a, n);
printf("排序好的數組為: ");
for (int k = 0; k < n; k++)
printf("%d ", a[k]);
printf("\n");
return 0;
}
分析:
最差、最優、平均時間復雜度都為O(n^2)。輔助空間為O(1)。穩定性:不穩定。
3.2.堆(Heap)排序 基本思想:先把數組構造成一個大頂堆(父親節點大于其子節點),然后把堆頂(數組最大值,數組第一個元素)和數組最后一個元素交換,這樣就把最大值放到了數組最后邊。把數組長度n-1,再進行構造堆,把剩余的第二大值放到堆頂,輸出堆頂(放到剩余未排序數組最后面)。依次類推,直至數組排序完成。
下圖為堆結構及其在數組中的表示。可以知道堆頂的元素為數組的首元素,某一個節點的左孩子節點為其在數組中的位置*2,其右孩子節點為其在數組中的位置*2+1,其父節點為其在數組中的位置/2(假設數組從1開始計數)。
下圖為怎么把一個無序的數組構造成一個大堆頂結構的數組的過程,注意其是從下到上,從右到左,從右邊第一個非葉子節點開始構建的。
代碼:
#include<stdio.h>
// 創建大堆頂,i為當節點,n為堆的大小
// 從第一個非葉子結點i從下至上,從右至左調整結構
// 從兩個兒子節點中選出較大的來與父親節點進行比較
// 如果兒子節點比父親節點大,則進行交換
void CreatHeap(int a[], int i, int n) {
// 注意數組是從0開始計數,所以左節點為2*i+1,右節點為2*i+2
for (; i >= 0; --i)
{
int left = i * 2 + 1; //左子樹節點
int right = i * 2 + 2; //右子樹節點
int j = 0;
//選出左右子節點中最大的
if (right < n) {
a[left] > a[right] ? j= left : j = right;
}
else
j = left;
//交換子節點與父節點
if (a[j] > a[ i]) {
int tmp = a[ i];
a[ i] = a[j];
a[j] = tmp;
}
}
}
// 進行堆排序,依次選出最大值放到最后面
void HeapSort(int a[], int n) {
//初始化構造堆
CreatHeap(a, n/2-1, n);
//交換第一個元素和最后一個元素后,堆的大小減1
for (int j = n-1; j >= 0; j--) {
//最后一個元素和第一個元素進行交換
int tmp = a[0];
a[0] = a[j];
a[j] = tmp;
int i = j / 2 - 1;
CreatHeap(a, i, j);
}
}
int main() {
int a[] = { 10,6,5,7,12,8,1,3,11,4,2,9,16,13,15,14 };
int n = sizeof(a) / sizeof(int);
HeapSort(a, n);
printf("排序好的數組為:");
for (int l = 0; l < n; l++) {
printf("%d ", a[l]);
}
printf("\n");
return 0;
}
分析:
最差、最優‘平均時間復雜度都為O(nlogn),其中堆的每次創建重構花費O(lgn),需要創建n次。輔助空間O(1)。穩定性:不穩定。
4. 歸并排序 基本思想:歸并算法應用到分治策略,簡單說就是把一個答問題分解成易于解決的小問題后一個個解決,最后在把小問題的一步步合并成總問題的解。這里的排序應用遞歸來把數組分解成一個個小數組,直到小數組的數位有序,在把有序的小數組兩兩合并而成有序的大數組。
下圖為展示如何歸并的合成一個數組。
下圖展示了歸并排序過程各階段的時間花費。
代碼:
#include <stdio.h>
#include <limits.h>
// 合并兩個已排好序的數組
void Merge(int a[], int left, int mid, int right)
{
int len = right - left + 1; // 數組的長度
int *temp = new int[len]; // 分配個臨時數組
int k = 0;
int i = left; // 前一數組的起始元素
int j = mid + 1; // 后一數組的起始元素
while (i <= mid && j <= right)
{
// 選擇較小的存入臨時數組
temp[k++] = a[ i] <= a[j] ? a[i++] : a[j++];
}
while (i <= mid)
{
temp[k++] = a[i++];
}
while (j <= right)
{
temp[k++] = a[j++];
}
for (int k = 0; k < len; k++)
{
a[left++] = temp[k];
}
}
// 遞歸實現的歸并排序
void MergeSort(int a[], int left, int right)
{
if (left == right)
return;
int mid = (left + right) / 2;
MergeSort(a, left, mid);
MergeSort(a, mid + 1, right);
Merge(a, left, mid, right);
}
int main() {
int a[] = { 5,1,9,2,8,7,10,3,4,0,6 };
int n = sizeof(a) / sizeof(int);
MergeSort(a, 0, n - 1);
printf("排序好的數組為:");
for (int k = 0; k < n; ++k)
printf("%d ", a[k]);
printf("\n");
return 0;
}
分析:
最差、最優、平均時間復雜度都為O(nlogn),其中遞歸樹共有lgn+1層,每層需要花費O(n)。輔助空間O(n)。穩定性:穩定。
完整的Word格式文檔51黑下載地址:
排序算法.docx
(447.23 KB, 下載次數: 9)
2018-10-11 14:56 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
歡迎光臨 (http://m.zg4o1577.cn/bbs/) |
Powered by Discuz! X3.1 |
主站蜘蛛池模板:
国产精品99久久久久久久久久久久
|
国产精品久久一区
|
av免费看网站
|
伊人网在线观看
|
好吊日在线视频
|
毛片网站视频
|
伊人在线视频
|
欧美成人三级
|
激情五月综合色婷婷一区二区
|
成人免费黄色片
|
欧美高清在线
|
午夜性视频
|
国产成人一区二区三区
|
日日拍夜夜拍
|
福利视频午夜
|
91精品久久久久久粉嫩
|
一级片在线|
成人欧美一区二区三区黑人免费
|
欧美久久一区二区
|
国产激情小说
|
国产午夜免费视频
|
五月天久久久
|
亚欧在线观看
|
国产农村妇女精品一二区
|
色爱av
|
国产精品毛片va一区二区三区
|
国产一区二区在线看
|
精品视频在线免费
|
婷婷久久五月天
|
日韩国产精品一区二区
|
老司机免费福利视频
|
天天躁日日躁狠狠躁av麻豆男男
|
国产精品久久久久永久免费看
|
久草中文在线
|
日韩精品一区在线
|
亚洲成人久久久
|
午夜免费视频
|
九月丁香婷婷
|
欧美亚洲在线
|
天堂网亚洲
|
91爱爱爱
|