卖逼视频免费看片|狼人就干网中文字慕|成人av影院导航|人妻少妇精品无码专区二区妖婧|亚洲丝袜视频玖玖|一区二区免费中文|日本高清无码一区|国产91无码小说|国产黄片子视频91sese日韩|免费高清无码成人网站入口

數(shù)據(jù)結(jié)構(gòu)實驗報告

數(shù)據(jù)結(jié)構(gòu)課程實驗報告題 目:姓 名:學 院:班 級:學 號: 互聯(lián)網(wǎng)域名查詢 信息科學與工程學院 ,實驗三樹和圖應用類實驗一、 問題定義及i 需求分析1. 問題描述互

數(shù)據(jù)結(jié)構(gòu)課程實驗報告

題 目:姓 名:

學 院:班 級:

學 號: 互聯(lián)網(wǎng)域名查詢 信息科學與工程學院

,

實驗三樹和圖應用類實驗

一、 問題定義及i 需求分析

1. 問題描述

互聯(lián)網(wǎng)域名系統(tǒng)是一個典型的樹形層次結(jié)構(gòu)。從根節(jié)點往下的第一層是頂層域,如cn 、com 等,最底層(第四層)是葉子結(jié)點,如www 等。因此,域名搜索可以看成是樹的遍歷問題。

2. 實驗要求

設計搜索互聯(lián)網(wǎng)域名的程序。

(1)采用樹的孩子兄弟鏈表等存儲結(jié)構(gòu)。

(2)創(chuàng)建樹形結(jié)構(gòu)。

(3)通過深度優(yōu)先遍歷搜索。

(4)通過層次優(yōu)先遍歷搜索。

3. 數(shù)據(jù)輸入的形式

輸入域名地址。如:www.sohu.com

4. 數(shù)據(jù)輸出的形式

輸出對應的ip 地址或者出錯時輸出“找不到服務器或發(fā)生DNS 錯誤”

二、概要設計

(1)為了實現(xiàn)上述程序的功能,應該以孩子兄弟鏈表存儲樹,所以需要樹的抽象數(shù)據(jù)類型。

(2)存入磁盤文件時還需要另一種文件的抽象數(shù)據(jù)類型。

(3)所有的域名和IP 都是以串的形式存的,所以還需要串的抽象數(shù)據(jù)類型。

(4)當用戶輸入站點的域名時,需要將域名分段存儲,在搜索時從最根部依次提出來與樹的節(jié)點域比較,由于用戶輸入是從最小級到最根級,彈出時與輸入順序相反,比如輸入“www.163.com ”,其中:www 是第三級,163是第二級,com 是第一級,所以再與樹節(jié)點比較時,首先比較com ,然后比較163,最后才比較www 。根據(jù)這種“后進先出”的關系,需要棧作為輔助工具,所以需要棧的抽象數(shù)據(jù)類型。

具體內(nèi)容:

1)樹的抽象數(shù)據(jù)類型

ADT Tree {

數(shù)據(jù)對象D :站點域名的集合。

數(shù)據(jù)關系R :{H}

(1)D 中存在惟一稱為根的數(shù)據(jù)元素root ,它在關系{H}下沒有前

驅(qū)。

(2)D-{root}之后可劃分為D 1, D 2, ?, Dn (n >0)對任意的劃分都兩

兩不相交。對任意的(i 1≤i ≤n ),惟一的存在數(shù)據(jù)元素Xi ∈Di ,

有?root , Xi ?∈H ;

(3)對應于D-{root}的劃分,H-{〈root ,Xi 〉}(i=1,2,?, n )有惟

一的一個劃分H 1, H 2, ?, Hn (n >0),對任意的j ≠k (i≤j , k ≤n )

1

,

有H j H k =Φ,并且對任意的i (1≤i ≤n ), H j 是Di 上的二元關系,(Di ,{Hi })是一顆符合本定義的樹,成為根root 的子樹。

基本操作P :

CreateChild (&T)

初始條件:樹根T 已經(jīng)存在。

操作結(jié)果:根據(jù)用戶輸入的域名建立此域名的樹鏈,并以T 為

樹根如用戶輸入www.cau.edu.cn ,則在建立起以T 為

根,cn 為T 的第一個孩子,www 為葉子的樹鏈,所

有的節(jié)點都鏈在孩子域。

InitialTree (&T)

操作結(jié)果:通過用戶輸入的數(shù)據(jù),構(gòu)造域名樹。其實是將建好的

域名樹鏈有序地插到樹中相應的位置。

Insert (&T)

初始條件:樹T 已經(jīng)存在。

操作結(jié)果:插入新的域名及IP 。

CreateTree (&T, *fp)

初始條件:包含樹的信息文件已經(jīng)存在,fp 為指向文件的指

針。

操作結(jié)果:通過從文件中讀取數(shù)據(jù),構(gòu)造域名樹。

DeleteTree (&T)

初始條件:T 已經(jīng)存在。

操作結(jié)果:銷毀樹,釋放空間。

} ADT Tree

2)文件的抽象數(shù)據(jù)類型

ADT File {

數(shù)據(jù)對象:D ={a i │a i ∈ElemSet, i =1,2, ?, n , n ≥0}

數(shù)據(jù)關系:R ={〈a i -1, a i 〉│a i -1, a i ∈D , i =1,2, ?, n }

基本操作:│

Save (&T)

初始條件:樹T 存在。

操作結(jié)果:先序遍歷樹,給葉子節(jié)點數(shù)據(jù)域賦IP 值,同時把相

關信息存入文件。

} ADT File

3)串的抽象數(shù)據(jù)類型

ADT String {

數(shù)據(jù)對象:D ={a i │a i ∈ElemSet, i =1,2, ?, n , n ≥0}

數(shù)據(jù)關系:R ={〈a i -1, a i 〉│a i -1, a i ∈D , i =1,2, ?, n }

基本操作:

CopyChar (&s, *a)

初始條件:a 是字符串常量。

操作結(jié)果:生成一個其值等于a 的串s 。

CopyStr (&s, a)

2

,

初始條件:a 是一個串。

操作結(jié)果:生成一個值等于a 的串s 。

CompareStr (a, b)

初始條件:a 和b 是兩個串。

操作結(jié)果:若a>b返回值>0;若a=b,返回值=0;若a

DeleteString (&s)

初始條件:串s 存在。

操作結(jié)果:銷毀串。

} ADT String

4)棧的抽象數(shù)據(jù)類型

ADT Stack {

數(shù)據(jù)對象:D ={a i │a i ∈ElemSet, i =1,2, ?, n , n ≥0}

數(shù)據(jù)關系:R ={〈a i -1, a i 〉│a i -1, a i ∈D , i =1,2, ?, n }約定a 1為棧底,a n 為

棧頂

基本操作:

InitialStack (&s)

操作結(jié)果:構(gòu)造一個空棧。

GetTop (s ,&e)

初始條件:棧s 已經(jīng)存在且非空。

操作結(jié)果:用e 返回棧s 的棧頂元素。

Push (&s, e)

初始條件:棧s 已經(jīng)存在且非空。

操作結(jié)果:插入元素e 為新的棧頂元素。

Pop (&s, &e)

初始條件:棧s 已經(jīng)存在且非空。

操作結(jié)果:刪除棧s 的棧頂元素,并用e 返回其值。

DeleteStack (&s)

初始條件:s 已經(jīng)存在。

操作結(jié)果:銷毀棧,釋放空間。

} ADT Stack

5)本程序5個模塊

本程序有5個模塊:主程序模塊,樹模塊(實現(xiàn)樹抽象數(shù)據(jù)類型),文件模塊(實現(xiàn)文件抽象數(shù)據(jù)類型),串模塊(實現(xiàn)串抽象數(shù)據(jù)類型),棧模塊(實現(xiàn)棧抽象數(shù)據(jù)類型)

3

,

三、詳細設計

typedef unsigned char String[30]; // 存放域名和IP 的串結(jié)構(gòu)

typedef struct TreeNode { // 樹的節(jié)點

ElemType data,IP; // 數(shù)據(jù)域(用來放域名)和IP 域(用來放IP )

struct TreeNode *firstchild,*nextsibling; // 指向孩子和兄弟的指針

// 兄弟表示同一層,孩子表示下一層

}TreeNode,*Tree;

typedef struct FileNode { // 存入文件的節(jié)點

ElemType data,IP; // 數(shù)據(jù)域(用來放域名)和IP 域(用來放IP )

int ltag,rtag; // 左右標志域:0表示無孩子,1表示有孩子

}FileNode;

typedef struct SNode {

SElemType data;

分開的一部分

struct SNode *next;

}SNode,*Stack;

(1)基本操作

Stack CreateWeb(){

// 用戶輸入域名時按 '.' 將域名分開分別放入鏈式棧中

// 最后將 "root" 入棧,為查找做準備,返回棧頂指針

CopyChar (root,"root" ); // 把 "root" 的值賦給串root InitialStack (webside ); // 初始化鏈式棧

do{

a =getchar(); // 輸入域名

4

// 用戶輸入的域名存在棧節(jié)點 // 數(shù)據(jù)域(用來存放域名被 '.' // 指針域,指向域名下一部分

,

for (int i=0;a!='.'&&a!='n';i ){

s[i]=a; a=getchar(); // 得到兩個 '.' 間的域名,將其值放

入一個串中

}

s[i]='0';

Push (webside,s ); // 將串的值入棧

}while(a!='n');

Push (webside,root ); // 將root 入棧

return webside; // 返回棧頂?shù)闹羔?/p>

} // CreateWeb

void Search(Tree T,Stack &webside,Tree &p){

// 用遞歸算法通過域名查找相應的IP ,返回相同層的指針

// 若存在則輸出IP ,若不存在則輸出相應的出錯信息

if (T&&webside->next!=NULL){

GetTop (webside,s ); // 取得域名棧頂元素

int t=CompareStr(s,T->data); // 比較域名和樹的數(shù)據(jù)域

if (t>0) Search (T->nextsibling,webside,p);

// 若域名比樹節(jié)點值大則遞歸搜索

樹節(jié)點兄弟

else if(t==0){

Pop (webside,s ); p=T; // 若域名和樹節(jié)點相同則

域名鏈式棧節(jié)點出棧

Search (T->firstchild,webside,p); // 繼續(xù)搜索樹節(jié)點的孩子,

即下一層

} // end else

} // end if

} // Search

(2)關于樹的操作

void CreateChild(Tree &T,Stack &webside){

// 用戶輸入一個網(wǎng)址域名,域名已經(jīng)被輸入到棧中,為域名建立相應的域名樹鏈

if (webside->next!=NULL){

t=new TreeNode; // 新開一個節(jié)點

Pop (webside,s ); // 從棧中取出域名第一部分

CopyStr (t->data,s); // 把第一部分賦值給樹節(jié)點的數(shù)據(jù)域

t->firstchild=t->nextsibling=NULL; // 把樹節(jié)點的孩子和兄弟鏈域暫置空

t->IP[0]='0'; // 把樹節(jié)點的IP 域置0

T->firstchild=t; // 讓根節(jié)點的孩子域指向新建的樹節(jié)點

CreateChild (t,webside ); // 再以此樹節(jié)點為根建立

5

,

新的樹節(jié)點,

// 直到把域名全部賦值到樹節(jié)點中

if (t->firstchild==NULL){

cout<<"請輸入域名IP"<

戶輸入IP

cin>>t->IP;

} // end if

} // end if

} // CreateChild

void Insert(Tree &T){

// 將域名樹鏈插入到樹T 中

do{

cout<<"請輸入站點域名:"<

webside=CreateWeb(); // 為用戶輸入的域名建立鏈表棧

Search (T,webside,p ); // 在樹中查找與域名節(jié)點相同的節(jié)點,

// 每一部分查找相匹配的樹節(jié)點,返回

指向

// 最后一個與域名節(jié)點相同的樹節(jié)點的

指針

if (p->firstchild==NULL){

if (p->IP[0]!='0') // 若發(fā)現(xiàn)輸入了重復的域名則給出提示

cout<<"你輸入了重復的域名"<

else CreateChild(p,webside ); // 若這個樹節(jié)點沒有孩子,則直接把新的

// 域名建立成新的樹,并讓這個樹節(jié)點孩

// 子域指向次新開的域名樹。

// 即將域名節(jié)點作為此樹節(jié)點的第一個孩

} // end if

else {

if (webside->next==NULL) // 若發(fā)現(xiàn)輸入了錯誤的域名,則給出相應

// 的提示

cout<<"你輸入了錯誤的域名!"<

else{

GetTop (webside,s ); // 若這個樹節(jié)點有孩子,則在他的孩子的

// 兄弟中找到新開域名樹應該插入的位置,

將其插入

6

// 若是葉子節(jié)點則要求用

,

t=p->firstchild;

a=CompareStr(t->data,s); // 比較域名與已經(jīng)存在的

兄弟節(jié)點

if (a>0){

CreateChild (p,webside ); // 若域名比兄弟節(jié)點小,則

前插

p->firstchild->nextsibling=t;

} // end if

else{

while (t->nextsibling!=NULL&&(a=CompareStr

(t->nextsibling->data,s))<0)

t=t->nextsibling; // 若域名比兄弟節(jié)點大,則后插

q=new TreeNode;

Pop (webside,s );

CopyStr (q->data,s);

q->firstchild=NULL;

q->IP[0]='0'; // 給新開節(jié)點賦值

q->nextsibling=t->nextsibling;

// 新開節(jié)點的兄弟指針指向插入處節(jié)//

點的兄弟

t->nextsibling=q; // 插入處的節(jié)點的兄弟指針指

向新開節(jié)點

CreateChild (q,webside ); // 把整個域名樹鏈插入

} // end else

} // end else

} // end else

DeleteStack (webside );

cout<<"是否要繼續(xù)輸入新域名? (y/n)"<

ch=getchar(); // 獲得用戶輸入的字符

getchar (); // 此為用戶輸入的回車

}while(ch=='y');

} // Insert

void InitialTree(Tree &T){

// 第一次由用戶輸入網(wǎng)站域名和IP ,建立節(jié)點有序的樹

T=new TreeNode; // 新開一個樹節(jié)點

CopyChar (T->data,"root"); // 建立樹的根節(jié)點

T->firstchild=T->nextsibling=NULL;

T->IP[0]='0';

Insert (T ); // 把新的域名樹鏈插入樹中

} // InitialTree

void CreateTree(Tree &T,FILE *fp){

// 文件已經(jīng)存在,從文件中讀出數(shù)據(jù),用遞歸算法先序遍歷構(gòu)建樹的孩子,兄弟二叉鏈表結(jié)構(gòu)

7

,

if (!feof (fp )){

T=new TreeNode; // 新建樹節(jié)點

f=new FileNode; // 新建文件節(jié)點用于讀取磁盤文件中的數(shù)據(jù)

if ((fread (f,sizeof (struct FileNode),1,fp ))!=1)

cout<<"無法打開文件!"<

CopyStr (T->data,f->data);

CopyStr (T->IP,f->IP); // 將文件節(jié)點的IP 的值賦給樹節(jié)點IP

if (f->ltag)

CreateTree (T->firstchild,fp); // 若樹節(jié)點有孩子則遞歸建立其孩子

else T->firstchild=NULL; // 若無孩子則孩子鏈域置為空

if (f->rtag)

CreateTree (T->nextsibling,fp); // 若樹節(jié)點有兄弟則遞歸建立其兄弟

else T->nextsibling=NULL; // 若無兄弟則兄弟鏈域置為空 delete f;

} // end if

} // CreateTree

void DeleteTree(Tree &T){

// 用遞歸算法銷毀樹,釋放空間

if (T ) {

DeleteTree (T->firstchild);

DeleteTree (T->nextsibling);

delete T;

} // end if

} // DeleteTree

// 銷毀樹的左子樹 // 銷毀樹的右子樹 // 銷毀樹的根節(jié)點

8

,

(3)串的操作

voidCopyStr (String &a,String b){

// 將串b 的值賦給串a(chǎn)

for (int i=0;b[i]!='0';i )a[i]=b[i];

賦給a

a[i]='0';

} // CopyStr

voidCopyChar (String &a,char* b){

// 將字符串b 的值賦給串a(chǎn)

for (int i=0;*b!='0';b ,i )a[i]=*b;

a[i]='0';

} // CopyStr

// 將b 數(shù)組中的值一個一個

int CompareStr(String a,String b){

// 串a(chǎn) 和b 從第一個字符開始比較,直到出現(xiàn)第一個不相同的字符為止

for (int i=0;a[i]!='0'&&b[i]!='0';i ) // 如果a>b,return >0;

if (a[i]!=b[i]) return a[i]-b[i]; // 如果a

if (a[i]!='0') return 1; // 如果a=b,return =0;

else if(b[i]!='0')return -1;

else return 0;

} // CompareStr

(4)棧的基本操作

void InitialStack(Stack &s){

// 初始化空棧

s=new SNode;

s->next=NULL;

} // InitialStack

voidPush (Stack &s,SElemType e){

// 將元素e 插入鏈式棧中,成為新的棧頂元素

p=new SNode; // 為新的棧頂元素分配空間 CopyStr (p->data,e); // 將e 的值賦給新節(jié)點數(shù)據(jù)域 p->next=s->next; // 插入新的棧頂元素

s->next=p; // 修改棧頂指針

} // Push

voidPop (Stack &s,SElemType &e){

// 若棧為空則給出相應的信息,若不空則刪除棧頂元素并將其值賦給e

if (!s->next) cout<<"空棧!"<

CopyStr (e,s->next->data); // 取出棧頂元素的值賦給e p=s->next; // 刪除棧頂元素

s->next=p->next;

9

// 新建一個棧頭節(jié)點 // 頭節(jié)點指向空

標簽: