抽象性設計——用C語言實現B樹的基本操作
這次做的是資料結構的一個抽象性實驗,我選擇的是B樹的基本操作。
編譯環境是:VS 2015
BTree.h
#include<stdio.h> #include<stdlib.h> #include<time.h> #define TRUE 1 #define FALSE 0 #define OVERFLOW -1 #define OK 1 #define ERROR 0 #define M 20//定義階數最大值 typedef int KeyType; typedef int Status; typedef struct { //記錄的結構定義 KeyType key; char data; }Record; typedef struct BTNode{ //B樹結點型別定義 int keynum; //結點中關鍵字個數,即結點的大小 KeyType key[M + 1]; //關鍵字,key[0]未用 struct BTNode *parent; //雙親結點指標 struct BTNode *ptr[M + 1];//孩子結點指標陣列 Record *recptr[M + 1]; //記錄指標向量,0號單元未用 }BTNode,*BTree; //B樹結點和B樹型別 typedef struct { BTree pt; //指向找到的結點 int i; //1<=i<=m,在結點中的關鍵字位序 int tag; //1:查詢成功,0:查詢失敗 }result,*resultPtr; //B樹的查詢結果型別 //介面定義 void CreatBTree(BTree&T, int n, int m); /* 初始條件:初始化關鍵字個數n大於等於0,B樹的階數m大於3小於等於20 操作結果:構建一顆階數為m,含有n個關鍵字的B樹 */ void SearchBTree(BTree T, int k, result &r); /* 初始條件:樹T存在 操作結果:在m階B數T上查詢關鍵字k,返回p{pt,i,tag} */ void InsertBTree(BTree &T, int k, BTree q, int i,int m); /* 初始條件:樹T存在 操作結果:在B樹T上結點p->pt的key[i]和key[i+1]之間插入關鍵字k */ void DeleteBTree(BTree p, int i, int m, BTree &T); /* 初始條件:B樹上p結點存在 操作結果:刪除B樹T上結點p->pt的關鍵字k */ void PrintBTree(BTree T); /* 初始條件:樹T存在 操作結果:中序遍歷B樹 */ void DestroyBTree(BTree T); /* 初始條件:樹T存在 操作結果:銷燬B樹 */ int menu(); /* 輸出選擇選單 */
OperationDefine.cpp
#include "BTree.h" void CreatBTree(BTree &T, int n, int m) {//構建一顆階數為m,含有n個關鍵字的B樹(3<=m<=M,0<=n<=10000) //建立B樹 int i, j; resultPtr p = NULL; p = (result*)malloc(sizeof(result)); srand((unsigned)time(NULL)); if (n == 0) printf("已成功初始化一棵空樹。\n"); else { for (j = 0; j < n; j++) { i = rand() % 1000;//生成隨機數i SearchBTree(T, i, *p);//查詢i插入位置 InsertBTree(T, i, p->pt, p->i, m); //進行插入 } printf("建立B樹成功!\n"); } } void PrintBTree(BTree T) { //中序遍歷B樹 int i = 1; if (NULL != T) { for (; i <= T->keynum; i++) { PrintBTree(T->ptr[i - 1]); printf("%d ", T->key[i]); } PrintBTree(T->ptr[i - 1]); } } int Search(BTree p, int k) { int i = 1; while (i <= p->keynum&&k > p->key[i]) i++; return i; } void SearchBTree(BTree T, int k, result &r) { //在m階B樹T上查詢關鍵字k,返回(pt,i,tag) //若查詢成功,則特徵值tag=1,指標pt所致結點中第i個關鍵字等於k;否則 //特徵值tag=0,等於k的關鍵字記錄應插入在指標pt所指結點中第i-1個和第i個關鍵字間 int i = 0, found = 0; BTree p = T, q = NULL; while (p != NULL && 0 == found) { i = Search(p, k);//在p->key[1..keynum]中查詢p->key[i-1]<k<=p->p->key[i] if (i > 0 && p->key[i] == k) found = 1;//找到待查關鍵字 else{ q = p; p = p->ptr[i - 1]; } } if (1 == found) {//查詢成功 r.pt = p; r.i = i; r.tag = 1; } else {//查詢不成功,返回key的插入位置i r.pt = q; r.i = i; r.tag = 0; } } void split(BTree &q, int s, BTree &ap) { //將q結點分裂成兩個結點,前一半保留,後一半移入新結點ap int i, j, n = q->keynum; ap = (BTNode*)malloc(sizeof(BTNode));//生成新結點ap ap->ptr[0] = q->ptr[s]; for (i = s + 1, j = 1; i <= n; i++, j++) {//後一半移入ap結點 ap->key[j] = q->key[i]; ap->ptr[j] = q->ptr[i]; } ap->keynum = n - s; ap->parent = q->parent; for (i = 0; i <= n - s; i++) { if (ap->ptr[i]) ap->ptr[i]->parent = ap;//將ap所有孩子結點指向ap } q->keynum = s - 1;//q結點的前一半保留,修改keynum } void newroot(BTree &T, BTree p, int x, BTree ap) {//生成新的根結點 T = (BTNode*)malloc(sizeof(BTNode)); T->keynum = 1; T->ptr[0] = p; T->ptr[1] = ap; T->key[1] = x; if (p != NULL) p->parent = T; if (ap != NULL) ap->parent = T; T->parent = NULL;//新根的雙親是空指標 } void Insert(BTree &q, int i, int x, BTree ap) {//x和ap分別插到q->key[i]和q->ptr[i] int j, n = q->keynum; for (j = n; j >= i; j--) { q->key[j + 1] = q->key[j];//關鍵字指標向後移一位 q->ptr[j + 1] = q->ptr[j];//孩子結點指標向後移一位 } q->key[i] = x;//賦值 q->ptr[i] = ap; if (ap != NULL) ap->parent = q; q->keynum++;//關鍵字數+1 } void InsertBTree(BTree &T, int k, BTree q, int i, int m) { //在B樹T上q結點的key[i-1]和key[i]之間插入關鍵字k //若引起結點過大,則沿雙親指標進行必要的結點分裂調整,使T仍是m階的B樹 int x, s, finished = 0, neednewroot = 0; BTree ap; if (NULL == q)//q為空,則新建根結點 newroot(T, NULL, k, NULL); else { x = k; ap = NULL; while (0 == neednewroot && 0 == finished) { Insert(q, i, x, ap);//key和ap分別插到q->key[i]和q->ptr[i] if (q->keynum < m) finished = 1;//插入完成 else {//分裂q結點 s = (m + 1) / 2; split(q, s, ap); x = q->key[s]; if (q->parent != NULL) { q = q->parent; i = Search(q, x);//在雙親結點中查詢x的插入位置 } else neednewroot = 1; } }//while if (1 == neednewroot)//T是空樹或者根結點已分裂為q和ap結點 newroot(T, q, x, ap);//生成含資訊(q,x,ap)的新的根結點T } } void Successor(BTree &p, int i) {//由後繼最下層非終端結點的最小關鍵字代替結點中關鍵字key[i]。 BTNode *temp; temp = p->ptr[i]; for (; NULL != temp->ptr[0]; temp = temp->ptr[0]) ;//找出關鍵字的後繼 p->key[i] = temp->key[1]; p = temp; } void Remove(BTree &p, int i) { //從結點p中刪除key[i] int j; int n = p->keynum; for (j = i; j < n; j++) { //關鍵字左移 p->key[j] = p->key[j + 1]; p->ptr[j] = p->ptr[j + 1]; } p->keynum--; } void Restore(BTree &p, int i, int m, BTree &T) {//調整B樹 int j; BTree ap = p->parent; BTree lc, rc, pr; int finished = 0, r = 0; while (0 == finished) { r = 0; while (ap->ptr[r] != p)//確定p在ap子樹的位置 r++; if (r == 0) { r++; lc = NULL; rc = ap->ptr[r]; } else if (r == ap->keynum) { rc = NULL; lc = ap->ptr[r - 1]; } else { lc = ap->ptr[r - 1]; rc = ap->ptr[r + 1]; } if (r > 0 && lc != NULL && (lc->keynum > (m - 1) / 2)) {//向左兄弟借關鍵字 p->keynum++; for (j = p->keynum; j > 1; j--) {//結點關鍵字右移 p->key[j] = p->key[j - 1]; p->ptr[j] = p->ptr[j - 1]; } p->key[1] = ap->key[r];//父親插入到結點 p->ptr[1] = p->ptr[0]; p->ptr[0] = lc->ptr[lc->keynum]; if (NULL != p->ptr[0])//修改p中的子女的父結點為p p->ptr[0]->parent = p; ap->key[r] = lc->key[lc->keynum];//左兄弟上移到父親位置 lc->keynum--; finished = 1; break; } else if (ap->keynum > r&&rc != NULL && (rc->keynum > (m - 1) / 2)) { p->keynum++; p->key[p->keynum] = ap->key[r];//父親插入到結點 p->ptr[p->keynum] = rc->ptr[0]; if (NULL != p->ptr[p->keynum]) {//修改p中的子女的父結點為p p->ptr[p->keynum]->parent = p; } ap->key[r] = rc->key[1];//右兄弟上移到父親位置 rc->ptr[0] = rc->ptr[1]; for (j = 1; j < rc->keynum; j++) {//右兄弟結點關鍵字左移 rc->key[j] = rc->key[j + 1]; rc->ptr[j] = rc->ptr[j + 1]; } rc->keynum--; finished = 1; break; } r = 0; while (ap->ptr[r] != p) r++;//重新確定p在ap子樹的位置 if (r > 0 && (ap->ptr[r - 1]->keynum <= (m - 1) / 2)) {//與左兄弟合併 lc = ap->ptr[r - 1]; p->keynum++; for (j = p->keynum; j > 1; j--) {//將p結點關鍵字和指標右移1位 p->key[j] = p->key[j - 1]; p->ptr[j] = p->ptr[j - 1]; } p->key[1] = ap->key[r];//父結點的關鍵字與p合併 p->ptr[1] = p->ptr[0];//從左兄弟右移一個指標 ap->ptr[r + 1] = lc; for (j = 1; j <= lc->keynum + p->keynum; j++) {//將結點p中關鍵字移到p左兄弟中 lc->key[lc->keynum + j] = p->key[j]; lc->ptr[lc->keynum + j] = p->ptr[j]; } if (p->ptr[0]) {//修改p中的子女的父結點為lc for (j = 1; j <= p->keynum; j++) { p->ptr[p->keynum + j]->parent = lc; } } lc->keynum = lc->keynum + p->keynum;//合併後的關鍵字個數 ap->keynum--; pr = p; free(pr);//釋放p結點空間 pr = NULL; p = lc; } else {//與右兄弟合併 rc = ap->ptr[r + 1]; if (r == 0) r++; p->keynum++; p->key[p->keynum] = ap->key[r];//父結點的關鍵字與p合併 p->ptr[p->keynum] = rc->ptr[0];//從右兄弟左移一個指標 rc->keynum = p->keynum + rc->keynum;//合併後關鍵字的個數 ap->ptr[r - 1] = rc; for (j = 1; j <= (rc->keynum - p->keynum); j++) {//將p右兄弟的關鍵字和指標右移 rc->key[p->keynum + j] = rc->key[j]; rc->ptr[p->keynum + j] = rc->ptr[j]; } for (j = 1; j <= p->keynum; j++) {//將結點p中關鍵字和指標移到p右兄弟中 rc->key[j] = p->key[j]; rc->ptr[j] = p->ptr[j]; } rc->ptr[0] = p->ptr[0]; if (p->ptr[0]) {//修改p中的子女的父結點為rc for (j = 1; j <= p->keynum; j++) { p->ptr[p->keynum + j]->parent = rc; } } for (j = r; j < ap->keynum; j++) {//將父結點中關鍵字和指標左移 ap->key[j] = ap->key[j + 1]; ap->ptr[j] = ap->ptr[j + 1]; } ap->keynum--;//父結點的關鍵字個數減1 pr = p; free(pr);//釋放p結點空間 pr = NULL; p = rc; } ap = ap->parent; if (p->parent->keynum >= (m - 1) / 2 || (NULL == ap&&p->parent->keynum > 0)) { finished = 1; } else if (NULL == ap) {//若調整後出現空的根結點,則刪除該根結點,樹高減1 pr = T; T = p;//根結點下移 free(pr); pr = NULL; finished = 1; } p = p->parent; } } void DeleteBTree(BTree p, int i, int m, BTree &T) { //刪除B樹上p結點第i個關鍵字 if (p->ptr[i - 1] != NULL) { Successor(p, i); //若不是最下層非終端結點 DeleteBTree(p, 1, m, T); //由後繼最下層非終端結點的最小關鍵字代替它 } else {//若是最下層非終端結點 Remove(p, i); //從結點p中刪除key[i] if (p->keynum < (m - 1) / 2) //刪除後關鍵字個數小於(m-1)/2 Restore(p, i, m, T); //調整B樹 } } void DestroyBTree(BTree T) { int i = 1; if (NULL != T) { for (; i <= T->keynum; i++) { DestroyBTree(T->ptr[i - 1]); free(T->ptr[i - 1]); } DestroyBTree(T->ptr[i - 1]); } } int menu() {//選單 int choice; printf("\n\n\t\t\t|**********************************************|\n"); printf("\t\t\t|**********************************************|\n"); printf("\t\t\t _____________請先建立B樹再進行操作!__________\n"); printf("\t\t\t| B樹測試介面 |\n"); printf("\t\t\t| |\n"); printf("\t\t\t| 1.建立B樹 2.B樹結點的查詢 |\n"); printf("\t\t\t| |\n"); printf("\t\t\t| 3.B樹結點的插入 4.B樹結點的刪除 |\n"); printf("\t\t\t| |\n"); printf("\t\t\t| 5.B樹的遍歷 6.B樹的銷燬 |\n"); printf("\t\t\t| |\n"); printf("\t\t\t| 0.退出 |\n"); printf("\t\t\t|______________________________________________|\n"); printf("\t\t\t|**********************************************|\n"); printf("\t\t\t|**********************************************|\n"); printf("\t\t\t| 15軟體工程(4)班 |\n"); printf("\t\t\t| 3115005372 |\n"); printf("\t\t\t| 楊宇傑 |\n"); printf("\t\t\t|********************S**************************|\n"); do { printf("\t\t\t請選擇功能(輸入1-6任意一個數字):"); scanf_s("%d", &choice); } while (choice<0||choice>6);//避免非法輸入 return choice; }
BTree_Test.cpp
#include<stdio.h> #include"BTree.h" int main() { BTree T=NULL; result r; int choice, k, i, m, n; do{ choice = menu(); if (choice >= 0 && choice <= 7) { system("cls");//把選單清除 switch (choice) { case 1: printf("請輸入B樹的階數m:(3<=m<=20)\n"); scanf_s("%d", &m); printf("請輸入B樹的初始化關鍵字個數:(0<=n<=10000)\n"); scanf_s("%d", &n); CreatBTree(T, n, m); break; case 2: printf("請輸入要查詢的關鍵字:\n"); scanf_s("%d", &k); SearchBTree(T, k, r); if (r.tag) { printf("該關鍵字的位置為該結點中第%d個關鍵字\n",r.i); } else { printf("該關鍵字不存在!\n"); } break; case 3: printf("請輸入要插入的關鍵字k:\n"); scanf_s("%d", &k); SearchBTree(T, k, r); InsertBTree(T, k, (&r)->pt, (&r)->i, m); printf("插入成功!\n"); break; case 4: printf("請輸入要刪除B樹T上的關鍵字:\n"); scanf_s("%d", &i); SearchBTree(T, i, r); DeleteBTree(r.pt, r.i, m, T); printf("刪除成功!\n"); break; case 5: printf("此時的B樹序列為:\n"); PrintBTree(T); printf("\n"); break; case 6: DestroyBTree(T); printf("銷燬成功!\n"); break; default:; } } }while (choice > 0 && choice < 7); return 0; }
相關推薦
抽象性設計——用C語言實現B樹的基本操作
這次做的是資料結構的一個抽象性實驗,我選擇的是B樹的基本操作。 編譯環境是:VS 2015 BTree.h #include<stdio.h> #include<stdlib.h> #include<time.h> #defi
C語言實現線性表基本操作
style eal struct fine fin delete class logs destroy #include <stdio.h> #include <tchar.h> #include <stdlib.h> #define
C語言-二叉樹基本操作以及二叉搜尋樹基本操作
功能 二叉樹操作: 建立二叉樹 遍歷二叉樹(前序,中序,後續) 計算高度 計算結點數目 清空二叉樹 空樹判斷 二叉搜尋樹操作: 插入 最值(最大值,最小值) 刪除 程式碼 #include &l
超全C語言二叉樹基本操作及講解
今天刷LeetCode上的題的時候,做到了關於二叉樹的題,於是決定把這一塊的知識整理一下。1、二叉樹的定義二叉樹通常以結構體的形式定義,如下,結構體內容包括三部分:本節點所儲存的值、左孩子節點的指標、右孩子節點的指標。這裡需要注意,子節點必須使用指標,就像我們定義結構體連結串
嚴蔚敏資料結構C語言實現棧的基本操作
int main(){ SqStack S; SElemType *e; int n,i; InitStack(&S); printf("請輸入需要入棧的資料個數\n"); scanf("%d",&n); for(i=0;i<n;i++) { sca
c語言實現圖的基本操作--鄰接矩陣儲存
利用鄰接矩陣容易判定任意兩個頂點之間是否有邊(或弧)相連,並容易求得各個頂點的度。 c語言程式碼實現如下: #include<stdio.h> #include<stdlib.h> #define MAX_VER_NUM 50 typedef cha
用C語言實現:將數組A中的內容和數組B中的內容進行交換(數組一樣大)。
image pri 之前 es2017 sys 變量 ret 只需要 題目 之前我們已經完成了對兩個變量內容進行交換的程序,這兩道題目大同小異,不過是將兩數變成了兩數組。 可能我們會想:我們是不是需要第三個數組作為中間變量進行交換操作? 答案是no,我們只需要通過一個循環體
【資料結構】二叉樹介面的實現(用c語言實現)
二叉樹 概念 一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根節點加上兩棵別稱為左子樹和右子樹的二又樹組成。 二叉樹的特點: 1.每個結點最多有兩棵子樹,即二叉樹不存在度大於2的結點。2.二又樹的子樹有左右之分,其子樹的次序不能顛倒 特殊的二
[原始碼和文件分享]基於C語言的B-樹的實現
1 軟體結構設計 1.1 軟體功能結構 用下圖所示的方式描述軟體的功能結構。 1.1.1 B-樹的查詢 B-樹的查詢過程:根據給定值查詢結點和在結點的關鍵字中進行查詢交叉進行。首先從根結點開始重複如下過程: 若比結點的第一個關鍵字小,則查詢在該結點第一個指標指向的結點進行;
用C語言實現二叉樹的結構和常用操作
#include<stdio.h> #include <stdlib.h> typedef float ElemType; typedef struct S_BiTNode//定義結點型別結構體 { ElemType data;//資料域 str
用C語言實現websocket服務器
sockaddr extend ++i set strlen ner ace == perl Websocket Echo Server Demo 背景 嵌入式設備的應用開發大都依靠C語言來完成,我去研究如何用c語言實現websocket服務器也是為了在嵌入式設備中實現一個
用C語言實現:將三個數按從大到小輸出。
temp clas 實現 ima 編程 程序 c語言實現 從大到小 code 這個題目用編程來實現非常簡單,由於我在上一篇博客中已經介紹過使用“冒泡排序”的方法。 所以我在這裏直接給出使用“冒泡排序”寫出的代碼: #include<stdio.h> int m
用C語言實現窗口抖動
clu 變量 win 句柄 span nbsp idt 兩個 spa #include "stdafx.h" #include <stdio.h> #include<Windows.h> int main() { int s
Linux終端程序用c語言實現改變輸出的字的顏色
光標位置 高亮 AI 藍色 屬性 用c語言實現 TE c語言 說明 顏色代碼: 格式: echo "\033[字背景顏色;字體顏色m字符串\033[0m" 例如: echo "\033[41;36m something here \033[0m" 其中41的位置代表
用c語言實現日誌功能
windows.h 用c語言實現 pause truct argc ifdef open info oid // 參考鏈接 // C語言實現寫入日誌文件 https://blog.csdn.net/sunlion81/article/details/8647028 #
用c++語言實現出四則運算的題
using div style cin 隨機函數 color 地方 switch ase 設計思路 1.利用隨機函數 隨機兩個兩位數 2.用其中一個數除以4取余函數 0 1,2,3 用switch語句分表代表加、減、乘、除。 3.輸出式子 4.利用for循環實現題的量增 5
用c語言實現單鏈表的逆序輸出
<span style="font-family: Arial, Helvetica, sans-serif;">可以用遞迴,如果沒到連結串列尾,則遞迴查詢,否則輸出當前值。下面只是演算法表示,不能直接放到程式裡編譯執行。</span><span style="fo
atoi函式的用法及用C語言實現ato
庫函式原型: #inclue <stdlib.h> int atoi(const char *nptr); 用法:將字串裡的數字字元轉化為整形數。返回整形值。 注意:轉化時跳過前面的空格字元,直到遇上數字或正負符號才開始做轉換,而再遇到非數字或字串結束時('/0')才結束
不依賴任何系統API,用c語言實現gbk/utf8/unicode編碼轉換
轉載地址:https://blog.csdn.net/bladeandmaster88/article/details/54837338 漢字'我' Unicode編碼是0x6211 01100010 00010001 UTF8編碼是&
用C語言實現最小二乘法演算法
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!