數據結構實驗10.1:內部排序的基本運算

文章目錄

  • 一,實驗目的
  • 二,實驗內容
      • 1. 數據生成與初始化
      • 2. 排序算法實現
        • (1)直接插入排序
        • (2)二分插入排序
        • (3)希爾排序
        • (4)冒泡排序
        • (5)快速排序
        • (6)簡單選擇排序
        • (7)堆排序
        • (8)二路歸并排序
      • 3. 統計與輸出
  • 三,實驗要求
      • (1)實驗步驟與要求
      • (2)注意事項
  • 四、數據結構設計
  • 五,示例代碼
    • 10-1.cpp源代碼
  • 六,操作步驟
  • 七,運行結果


一,實驗目的

  1. 深入理解排序原理:掌握排序的基本概念、分類及穩定性等特性,明確不同排序算法的適用場景。
  2. 熟練實現經典算法:通過編碼實現直接插入、二分插入、希爾、冒泡、快速、簡單選擇、堆、二路歸并等8種排序算法,加深對算法邏輯的理解。
  3. 提升算法應用能力:運用排序算法解決實際數據處理問題,通過統計比較次數和移動次數量化分析算法效率,增強算法優化思維。

二,實驗內容

1. 數據生成與初始化

  • 使用隨機數函數 rand() 生成范圍在 [1, MAXNUM-1] 的隨機整數序列(MAXNUM 設為100),確保序列長度可由用戶指定(1~99)。
  • 示例序列(假設長度為8):[49, 38, 65, 97, 76, 13, 27, 49]

2. 排序算法實現

(1)直接插入排序
  • 思想:從第二個元素開始,將當前元素插入到已排序子序列的合適位置,通過順序比較和移動實現。
  • 穩定性:穩定。
(2)二分插入排序
  • 優化:利用二分查找確定插入位置,減少比較次數,移動次數與直接插入相同。
  • 穩定性:穩定。
(3)希爾排序
  • 思想:按增量序列分組,對每組進行直接插入排序,逐步縮小增量至1。
  • 增量序列5, 3, 1(示例)。
  • 穩定性:不穩定。
(4)冒泡排序
  • 思想:相鄰元素比較,逆序時交換,每趟將最大元素“冒泡”到末尾。
  • 優化:設置標記change,若某趟無交換則提前終止。
  • 穩定性:穩定。
(5)快速排序
  • 思想:選擇基準值,通過分區操作將序列分為兩部分,遞歸排序。
  • 分區策略:Hoare法(左右指針交替移動)。
  • 穩定性:不穩定。
(6)簡單選擇排序
  • 思想:每趟選擇未排序部分的最小元素,與當前位置交換。
  • 穩定性:不穩定(相同元素相對順序可能改變)。
(7)堆排序
  • 思想:構建大頂堆,每次將堆頂元素與末尾元素交換,調整堆結構。
  • 步驟:建堆 → 交換堆頂與末尾 → 調整堆。
  • 穩定性:不穩定。
(8)二路歸并排序
  • 思想:遞歸分割序列,合并兩個有序子序列。
  • 輔助空間:需要額外數組存儲臨時合并結果。
  • 穩定性:穩定。

3. 統計與輸出

  • 比較次數(cp):記錄關鍵字比較操作的總次數。
  • 移動次數(mv):記錄元素賦值操作的總次數(如交換、插入等)。
  • 輸出內容
    • 原始序列與排序后序列;
    • 各算法的比較次數和移動次數;
    • 算法效率對比表格。

三,實驗要求

(1)實驗步驟與要求

  1. 代碼補全

    • 參照提供的參考程序,補全各算法中缺失的代碼(如循環條件、指針移動邏輯等),確保算法邏輯正確。
    • 示例補全點
      • 快速排序分區函數中左右指針的移動條件(j--/i++);
      • 冒泡排序的交換標記change初始化與更新。
  2. 調試與測試

    • 測試用例
      • 隨機序列(如長度10、50、99);
      • 特殊序列(正序、逆序、重復元素多的序列)。
    • 調試要點
      • 確保隨機數生成正確,無越界訪問;
      • 驗證各算法排序結果是否正確,統計計數器(cpmv)是否準確。
  3. 數據記錄與分析

    • 表格示例
排序算法比較次數(cp)移動次數(mv)耗時(ms)穩定性
直接插入排序352812穩定
快速排序22155不穩定
  • 分析方向
    • 比較次數與序列初始有序度的關系(如冒泡排序在正序時比較次數最少);
    • 移動次數與算法特性的關聯(如歸并排序移動次數較多但比較次數穩定);
    • 穩定性對特定場景的影響(如穩定排序適用于多關鍵字排序)。

(2)注意事項

  • 空間復雜度:歸并排序需要額外空間(O(n)),其他算法多為原地排序(O(1),除堆排序的輔助空間)。
  • 時間復雜度對比
    • 最優/平均情況:快速排序、歸并排序(O(n log n));
    • 最壞情況:直接插入、冒泡、簡單選擇(O(n2))。
  • 代碼規范:添加必要注釋,確保變量命名清晰(如cp為comparison count,mv為movement count)。

四、數據結構設計

#define MAXNUM 100
typedef int KeyType;				// 定義關鍵字類型為整型
typedef struct {
KeyType	key;					// 關鍵字項int 		other;				// 其他數據項
}ElemType;						// 元素類型
typedef struct {ElemType	r[MAXNUM+1];  // r[0]閑置或用作哨兵int 			length;			// 待排序元素個數
} SqList;							// 順序表類型

五,示例代碼

10-1.cpp源代碼

#define MAXNUM 100
#define TRUE 1
#define FALSE 0
#include<stdio.h>
#include<stdlib.h>
#include<time.h>typedef int KeyType;
typedef struct {			// 定義元素的結構類型KeyType  key;	int      other;
} ElemType;typedef struct {			// 定義排序表結構類型ElemType r[MAXNUM+1];int length;
} SqList;//(1)創建隨機數排序表
void CreatList(SqList &L) {int i;do {printf("  輸入排序表長度(1-%d)==>", MAXNUM-1);scanf("%d", &L.length);} while(L.length<1 || L.length>MAXNUM-1);srand((unsigned)time(NULL));for(i=1; i<=L.length; i++) 			// 隨機產生排序表L.r[i].key = 1 + rand()%(MAXNUM-1);
}// (2)直接插入排序
void InsertSort(SqList &L, int &cp, int &mv) {int i, j;for(i=2; i<=L.length; i++) {cp++;if (L.r[i].key < L.r[i-1].key) {L.r[0] = L.r[i]; mv++;for(j=i-1; L.r[0].key < L.r[j].key; j--) {L.r[j+1] = L.r[j]; cp++; mv++;}cp++; L.r[j+1] = L.r[0]; mv++;}//if}
}// (3)折半插入排序
void BinSort(SqList &L, int &cp, int &mv)  {int i, j, low, high, mid;for(i=2; i<=L.length; i++) {L.r[0] = L.r[i]; mv++;low = 1; high = i-1;while(low <= high) {		// 定位插入點mid = (low + high)/2;  cp++;if (L.r[0].key < L.r[mid].key) high = mid-1;else low = mid+1;}for(j=i-1; j>=high+1; j--) {	L.r[j+1] = L.r[j]; mv++;}L.r[high+1] = L.r[0]; mv++;}
}// (4)希爾排序
void ShellInsert(SqList &L, int dk, int &cp, int &mv)  {//對順序表L作一趟希爾排序int i, j;for(i=dk+1; i<=L.length; i++) {cp++;if(L.r[i].key < L.r[i-dk].key) {		//需將L.r[i]插入有序增量子表mv++;L.r[0] = L.r[i];  			//L.r[i]暫存入L.r[0]for(j=i-dk; j>0 && L.r[0].key < L.r[j].key; j-=dk) {   L.r[j+dk] = L.r[j]; 		//尋找插入位置時記錄后移cp++; mv++;}cp++; mv++; L.r[j+dk] = L.r[0];    //插入}//if}//for
} //ShellInsertSortvoid ShellSort(SqList &L, int &cp, int &mv)  {//按增量序列5,3,1進行希爾排序ShellInsert(L, 5, cp, mv);     //一趟增量為5的希爾排序ShellInsert(L, 3, cp, mv);     //二趟增量為3的希爾排序ShellInsert(L, 1, cp, mv);     //三趟增量為1的希爾排序
} //ShellInsertSort//(5)冒泡排序
void BubbleSort(SqList &L, int &cp, int &mv)  {int i, j, change;for(i = 1, change = TRUE; i < L.length && change; i++) {change = FALSE;for(j = 1;  j < L.length - i + 1;  ++j) {	cp++;if (L.r[j].key > L.r[j+1].key) {L.r[0] = L.r[j];    L.r[j] = L.r[j+1]; L.r[j+1] = L.r[0];  change = TRUE; mv += 3;}//if} //for         }//for
} // BubbleSort//(6)快速排序
int Partition(SqList &L, int low, int high, int &cp, int &mv) {int i, j;KeyType pivotkey;L.r[0] = L.r[low]; mv++; pivotkey = L.r[0].key; i = low; j = high;while (i < j) {while (i < j && L.r[j].key >= pivotkey) {j--; cp++;}if(i < j)  cp++;L.r[i] = L.r[j]; mv++;while (i < j && L.r[i].key <= pivotkey) {i++; cp++;}if(i < j)  cp++;L.r[j] = L.r[i]; mv++;}L.r[i] = L.r[0]; mv++;return i;
}//Partitionvoid QSort(SqList &L, int low, int high, int &cp, int &mv)  {//對L.r[low]~L.r[high]的元素進行快速排序int pivotloc;if (low < high) { pivotloc = Partition(L, low, high, cp, mv);    //一趟劃分QSort(L, low, pivotloc-1, cp, mv);QSort(L, pivotloc+1, high, cp, mv);}//if
} //QSort//(7)簡單選擇排序
void SelectSort(SqList &L, int &cp, int &mv)  {//對順序表作簡單選擇排序int i, j, k;				// j保存剩余元素中最小值元素的下標for(i=1; i<L.length; i++) {for(k=i, j=i; k<=L.length; k++) {cp++;if(L.r[k].key < L.r[j].key)    j = k;}if (j != i)  {L.r[0] = L.r[i]; L.r[i] = L.r[j]; L.r[j] = L.r[0]; mv += 3;} } //for          
} // SelectSort//(8)堆排序
void HeapAdjust(SqList &H, int s, int m, int &cp, int &mv) {// H.r[s .. m]中除H.r[s].key外均滿足堆的定義// 調整H.r[s]的關鍵字,使H.r[s .. m]成為一個大頂堆int j;H.r[0] = H.r[s];  mv++;for(j=2*s; j<=m; j*=2) {      //沿key較大的孩子結點向下篩選if(j<m && H.r[j].key < H.r[j+1].key) ++j; //j為key較大的記錄的下標        if(j<m)  cp++;cp++;  if(H.r[0].key >= H.r[j].key)  break; H.r[s] = H.r[j];    //較大的孩子結點值換到父結點位置mv++;s = j;}H.r[s] = H.r[0]; mv++;    //H.r[0]應插入的位置在s處
} // HeapAdjustvoid HeapSort(SqList &H, int &cp, int &mv) {  //對順序表H進行堆排序int i;for(i=H.length/2; i>0; --i)        // 把H建成大頂堆HeapAdjust(H, i, H.length, cp, mv);for(i=H.length; i>1; --i) {H.r[0] = H.r[1]; H.r[1] = H.r[i]; H.r[i] = H.r[0]; mv += 3;//堆頂記錄和當前未排子序列中最后一個記錄相交換HeapAdjust(H, 1, i-1, cp, mv); //將H.r[1 .. i - 1] 重新調整為大頂堆 }
}// HeapSort //(9)二路歸并排序
void Merge(SqList &L, SqList &temp, int i, int m, int n, int &cp, int &mv) 
{	// 引入輔助空間tempint b = i, j, k;for(j = m+1, k = 1; i <= m && j <= n; ++k) {if (L.r[i].key < L.r[j].key) temp.r[k] = L.r[i++];else temp.r[k] = L.r[j++];cp++; mv++;}for (; i <= m; ) {temp.r[k++] = L.r[i++]; mv++;}for (; j <= n; ) {temp.r[k++] = L.r[j++]; mv++;}for(i = b, k = 1; i <= n; )  {L.r[i++] = temp.r[k++]; mv++;}
} // Mergevoid MergeSort(SqList &L, SqList &temp, int s, int t, int &cp, int &mv)  {//歸并排序int m;if (s < t) {m = (s + t)/2;MergeSort(L, temp, s, m, cp, mv);MergeSort(L, temp, m+1, t, cp, mv);Merge(L, temp, s, m, t, cp, mv);   //合并L.r[s]~L.r[m]與L.r[m+1]~L.r[t]}//if
} // MergeSort//(10)輸出排序表
void OutputList(SqList L)  {int i;for(i=1; i<=L.length; i++)printf("%3d", L.r[i].key);printf("\n");
}int main() {SqList LL, L;		//LL為待排序表,L為排序表SqList temp;		//二路歸并算法中所使用的臨時順序表int cp, mv;		//cp記錄元素關鍵字比較次數,mv記錄元素移動次數printf("(1)創建隨機數排序表......\n");CreatList(LL);		//待排序序列保存在LL表中printf("  排序表輸出:");OutputList(LL);getchar();printf("(2)直接插入排序......\n");L = LL; cp = mv = 0;InsertSort(L, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(3)折半插入排序......\n");L = LL; cp = mv = 0;BinSort(L, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(4)希爾排序......\n");L = LL; cp = mv = 0;ShellSort(L, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(5)冒泡排序......\n");L = LL; cp = mv = 0;BubbleSort(L, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(6)快速排序......\n");L = LL; cp = mv = 0;QSort(L, 1, L.length, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(7)簡單選擇排序......\n");L = LL; cp = mv = 0;SelectSort(L, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(8)堆排序......\n");L = LL; cp = mv = 0;HeapSort(L, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);getchar();printf("(9)二路歸并排序......\n");L = LL; cp = mv = 0;MergeSort(L, temp, 1, L.length, cp, mv);printf("  排序結果:");OutputList(L);printf("  排序效率:比較次數%d,移動次數%d。\n", cp, mv);return 0;
}

六,操作步驟

1,雙擊Visual Studio程序快捷圖標,啟動程序。
在這里插入圖片描述

2,之前創建過項目的話,直接打開即可,這里選擇【創建新項目】。
在這里插入圖片描述

3,單擊選擇【空項目】——單擊【下一步】按鈕。
在這里插入圖片描述

4,編輯好項目的名稱和存放路徑,然后單擊【創建】按鈕。
在這里插入圖片描述

5,創建C++程序文件,右擊【源文件】——選擇【添加】——【新建項】。
在這里插入圖片描述
6,輸入項目名稱10-1.cpp,單擊【添加】按鈕。
在這里插入圖片描述

7,編寫代碼,單擊運行按鈕,運行程序。
在這里插入圖片描述

七,運行結果

1,實驗要求的測試結果。
在這里插入圖片描述

2,編寫代碼測試測試的結果。
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81572.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81572.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81572.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從秒開到絲滑體驗!WebAssembly助力ZKmall商城重構 B2B2C 商城性能基線

在 B2B2C 電商領域&#xff0c;用戶對頁面加載速度與交互流暢度的要求日益嚴苛。傳統 Web 技術在處理復雜業務邏輯、海量數據渲染時&#xff0c;常出現卡頓、延遲等問題&#xff0c;導致用戶流失。ZKmall 商城創新性地引入 WebAssembly&#xff08;簡稱 Wasm&#xff09;技術&a…

FD+Mysql的Insert時的字段賦值亂碼問題

方法一 FDQuery4.SQL.Text : INSERT INTO 信息表 (中心, 分組) values(:中心,:分組); FDQuery4.Params[0].DataType : ftWideString; //必須加這個數據類型的定義&#xff0c;否則會有亂碼 FDQuery4.Params[1].DataType : ftWideString; //ftstring就不行&#xff0c;必須是…

vue2.0 組件生命周期

個人簡介 &#x1f468;?&#x1f4bb;?個人主頁&#xff1a; 魔術師 &#x1f4d6;學習方向&#xff1a; 主攻前端方向&#xff0c;正逐漸往全棧發展 &#x1f6b4;個人狀態&#xff1a; 研發工程師&#xff0c;現效力于政務服務網事業 &#x1f1e8;&#x1f1f3;人生格言&…

使用GmSSL v3.1.1實現SM2證書認證

1、首先使用gmssl命令生成根證書、客戶端公私鑰&#xff0c;然后使用根證書簽發客戶端證書&#xff1b; 2、然后編寫代碼完成認證功能&#xff0c;使用根證書驗證客戶端證書是否由自己簽發&#xff0c;然后使用客戶端證書驗證客戶端私鑰對隨機數的簽名是否正確。 第一部分生成根…

升級mysql (rpm安裝)

#備份以防萬一 備份配置文件: /etc/my.cnf.d/server.cnf 備份數據: mysqldump -u your_username -p --all-databases > all_databases.sql #停止 systemctl stop mysql #卸載舊版 yum remove mariadb #安裝新版( 通過yum安裝報錯,死活安裝不了,只能rpm安裝) 下載地址…

深入理解pip:Python包管理的核心工具與實戰指南

# 深入理解pip&#xff1a;Python包管理的核心工具與實戰指南 在Python開發中&#xff0c;第三方庫是提升效率的關鍵。而pip作為Python官方的包管理工具&#xff0c;承擔著安裝、卸載、升級和管理庫的重要職責。本文將全面解析pip的核心命令&#xff0c;結合實例演示用法&#…

Linux配置SSH密鑰認證

介紹 配置SS秘鑰認證后&#xff0c;可以通過shell腳本免密刪除文件或執行命令。 # 生成密鑰對&#xff08;如果還沒有&#xff09; ssh-keygen -t rsa# 將公鑰復制到服務器 ssh-copy-id "$remote_user$remote_host"

python打卡第30天

知識點回顧&#xff1a; 一&#xff0c;導入官方庫的三種手段。 使用 import 直接導入整個模塊 import module_name 使用 from ... import ... 導入特定功能 from module_name import function_name 使用 as 關鍵字重命名模塊或功能 import module_name as alias # 或 from mod…

Java基礎(網絡編程)

一、概述 目的&#xff1a;網絡通信&#xff1a; 1、設備和設備 2、進程和進程 1&#xff09;不同設備之間 2&#xff09;本地設備之間 需要解決的問題&#xff1a; 如何準確地發送到對方的主機 - IP地址 - 唯一的定位網絡中的一臺主機 如何準確的發送到對方主機的進程 -…

第二屆parloo杯的RSA_Quartic_Quandary

&#xff08;害&#xff0c;還是太菜了&#xff0c;上去秒了一道題之后就動不了了&#xff0c;今晚做個記錄&#xff0c;一點點的往回拾起吧&#xff09; # from Crypto.Util.number import getPrime, bytes_to_long # import math # # FLAG b************** # # # def gene…

RL?_ Better Test-Time Scaling by Unifying LLM Reasoners With Verifiers

RL?: Better Test-Time Scaling by Unifying LLM Reasoners With Verifiers 在人工智能領域&#xff0c;大語言模型&#xff08;LLM&#xff09;的推理能力提升一直是研究熱點。今天要解讀的論文提出了一種全新的強化學習框架RL?&#xff0c;通過融合推理與驗證能力&#xf…

VS中將控制臺項目編程改為WINDOWS桌面程序

有時候因為誤操作&#xff0c;建立了控制臺項目&#xff0c;但是實際上想建立桌面程序。那么應該如何改過來呢&#xff1f; 一共要修改兩個地方&#xff0c;修改步驟如下&#xff1a; 第一處修改地點&#xff1a; 將C/C下面的預處理器選項中&#xff0c;將原本的_CONSOLE修改…

API Gateway REST API 集成 S3 服務自定義 404 頁面

需求分析 使用 API Gateway REST API 可以直接使用 S3 作為后端集成對外提供可以訪問的 API. 而當訪問的 URL 中存在無效的桶, 或者不存在的對象時, API Gateway 默認回向客戶端返回 200 狀態碼. 而實際上這并不是正確的響應, 本文將介紹如何自定義返回 404 錯誤頁面. 基本功…

【達夢數據庫】過程、函數、包頭和包體詳解零基礎

目錄 背景參考鏈接解釋包頭包體 背景 最近遇到關于包頭和包體的問題&#xff0c;學習并記錄 參考鏈接 參考鏈接: oracle的過程、函數、包頭和包體詳解零基礎 解釋 包頭主要用于定義接口&#xff0c;包體主要用以實現包體中聲明的存儲過程、函數等。 包頭 包體

C++字符串處理:`std::string`和`std::string_view`的區別與使用

在 C中&#xff0c;std::string和std::string_view都用于處理字符串&#xff0c;但它們的用途和性能特點有很大不同。本教程將通過代碼示例和流程圖&#xff0c;幫助你快速掌握它們的使用方法。 1.什么是std::string和std::string_view&#xff1f; 1.1std::string std::str…

Pod 節點數量

動態調整 在 Kubernetes 中&#xff0c;如果為量化交易系統的 Pod 設置了可伸縮&#xff08;HPA / VPA / 自定義控制器&#xff09;&#xff0c;并且默認副本數是 5&#xff0c;那么節點數量&#xff08;副本數&#xff09;是否變化&#xff0c;主要取決于以下幾個因素。 ? …

基于OpenCV中的圖像拼接方法詳解

文章目錄 引言一、圖像拼接的基本流程二、代碼實現詳解1. 準備工作2. 特征檢測與描述detectAndDescribe 函數詳解&#xff08;1&#xff09;函數功能&#xff08;2&#xff09;代碼解析&#xff08;3&#xff09;為什么需要這個函數&#xff1f;&#xff08;4&#xff09;輸出數…

Java-List集合類全面解析

Java-List集合類全面解析 前言一、List接口概述與核心特性1.1 List在集合框架中的位置1.2 List的核心特性1.3 常見實現類對比 二、ArrayList源碼剖析與應用場景2.1 內部結構與初始化2.2 動態擴容機制2.3 性能特點與最佳實踐 三、LinkedList 源碼剖析與應用場景3.1 內部結構與節…

Flink 并行度的設置

在 Apache Flink 中&#xff0c;并行度&#xff08;Parallelism&#xff09; 是控制任務并發執行的核心參數之一。Flink 提供了 多個層級設置并行度的方式&#xff0c;優先級從高到低如下&#xff1a; &#x1f9e9; 一、Flink 并行度的四個設置層級 層級描述設置方式Operator…

OpenCV 筆記(39):頻域中的拉普拉斯算子

1. 拉普拉斯算子 在該系列的第八篇文章中&#xff0c;我們曾經介紹過在二維空間拉普拉斯算子的定義為&#xff1a; 這是對函數 的二階偏導數之和。 2. 拉普拉斯算子的傅里葉變換及其推導 在該系列的第三十二篇文章中&#xff0c;我們曾給介紹過下面的公式 二維連續傅里葉變換&…