數據結構實驗報告二

1.以二叉鏈表爲存儲結構,實現二叉樹的創建、遍歷

1)問題描述:在主程序中設計一個簡單的菜單,分別調用相應的函數功能:

       1…建立樹

       2…前序遍歷樹

       3…中序(非遞歸)遍歷樹

4…後序遍歷樹

       0…結束

2)實驗要求:在程序中定義下述函數,並實現要求的函數功能: 

CreateTree():按從鍵盤輸入的前序序列,創建樹

    PreOrderTree():前序遍歷樹(遞歸)

    InOrderTree():中序(非遞歸)遍歷樹

    LaOrderTree(): 後序遍歷樹(遞歸)

3)注意問題:

   注意理解遞歸算法的執行步驟。

   注意字符類型數據在輸入時的處理。

   重點理解如何利用棧結構實現非遞歸算法

#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
	int data;
	BiTNode* lchild,*rchild;
};
typedef BiTNode* BiTree;

int STree(BiTree r,int a,int b){
	int flag;
	if(r == NULL) return 0;
    if(r->data == a){
    	if(r->lchild == NULL){
    		r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
    		r->lchild->data = b;
			r->lchild->lchild = NULL;
			r->lchild->rchild = NULL;
			return 1; 
		}
		else if(r->rchild == NULL){
			r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
			r->rchild->data = b;
			r->rchild->lchild = NULL;
			r->rchild->rchild = NULL;
			return 1; 
		}
	}
	else{
		flag = STree(r->lchild,a,b);
	    if(flag != 1){
		    flag = STree(r->rchild,a,b);			
		}
	}
	return flag;
} 

int count = 1;
void PreOrderTree(BiTree root,int m){
	if(root == NULL) return;
	if(m != count){
	    printf("%d ",root->data);
		count++;		
	}
    else{
    	printf("%d\n",root->data);
	}
	PreOrderTree(root->lchild,m);
	PreOrderTree(root->rchild,m);
} 

int count1 = 1;
void InOrderTree(BiTree root,int m){
	BiTree p,stack[100];
	int top = 0;
	if(root == NULL) return;
	p = root;
	while(!(p == NULL && top == 0)){
		while(p != NULL){
			if(top<99){
				stack[top] = p;
				top++;
			}
			else{
				printf("棧溢出");
				return; 
			}
			p = p->lchild; 
		}
		if(top<=0) return;
		else{
			top--;
			p = stack[top];
	            if(m != count1){
	                printf("%d ",p->data);
		            count1++;		
	            }
                else{
    	            printf("%d\n",p->data);
	            }

			p = p->rchild;
		}
	} 
}

int count2 = 1;
void LaOrderTree(BiTree root,int m){	
	if(root == NULL) return;
	LaOrderTree(root->lchild,m);
	LaOrderTree(root->rchild,m);
	if(m != count2){
	    printf("%d ",root->data);
		count2++;		
	}
    else{
    	printf("%d\n",root->data);
	}
} 

int main(){
	int n,count=0,k,m;
	BiTree t;
	t = (BiTNode*)malloc(sizeof(BiTNode));
	cout<<"1...建立樹"<<endl;
	cout<<"2...前序遍歷樹"<<endl;
	cout<<"3...中序(非遞歸)遍歷樹"<<endl;
	cout<<"4...後序遍歷樹"<<endl;
	cout<<"0...結束"<<endl; 
	while(1){
		scanf("%d",&k);
		if(k==1){
			printf("請建立樹:\n"); 
			scanf("%d",&n);   //輸入節點個數 
            m=n;
	        if(n!=0){
	        while(n-1){
	            int a,b;
	            scanf("%d%d",&a,&b);
	            if(count == 0){
	   	            t->data = a;
	   	            t->lchild = NULL;
	   	            t->rchild = NULL;
	   	            count++;
	            }
	            STree(t,a,b);
	            n--;
	        }
	        }
		}
		else if(k==2){
			printf("前序遍歷樹\n");
			PreOrderTree(t,m);	
			cout<<endl;
		} 
		else if(k==3){
			printf("中序遍歷樹\n");
			InOrderTree(t,m);
			cout<<endl;
		}
		else if(k==4){
			printf("後序遍歷樹\n");
			LaOrderTree(t,m);
			cout<<endl;
		}
		else if(k==0){
			break;
		}
	}
	return 0;
}

2.在二叉樹中,P所指結點爲二叉樹中任一給定的結點,編寫算法求從根結點到P所指結點之間的路徑。

   實驗要求:以二叉鏈表作爲存儲結構

   實驗提示:採用非遞歸後序遍歷二叉樹,當後序遍歷訪問到P所指結點時,此時棧中所有結點均爲P所指結點的祖先,由這些祖先便構成了一條從根結點到P所指結點之間的路徑。

#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
	int data;
	BiTNode *lchild,*rchild;
};
typedef BiTNode *BiTree;
typedef struct{
	BiTree link;
	int flag;
}StackType;

void LaOrderTree(BiTree root,int p){   //後序遍歷非遞歸實現 
	StackType stack[100];
	BiTree q;
	int top,sign;
	if(root == NULL) return;
	top = -1;
	q = root;
	while(!(q==NULL && top==-1)){
		if(q!=NULL){
			top++;
			stack[top].link = q;
			stack[top].flag = 1;
			q = q->lchild;
		}
		else{
			q = stack[top].link;
			sign = stack[top].flag;
			top--;
			if(sign==1){
				top++;
				stack[top].link = q;
				stack[top].flag = 2;
				q = q->rchild;
			}
			else{
	            char tmp[100];
                int i=0,length;
                if(q->data == p){
                    length = top+1;
                	tmp[i] = p;
                	while(top != -1){
						q = stack[top].link;
                		tmp[++i] = q->data;
                		top--;
					}
					cout<<endl; 
					cout<<"路徑爲:"<<endl;
					while(length>0){
						printf("%d ",tmp[length]);
						length--;
					}	
					printf("%d",tmp[0]);
					break;
				}
				q = NULL;
			}
		}
	}
} 

int STree(BiTree r,int a,int b){
	int flag;
	if(r == NULL) return 0;
    if(r->data == a){
    	if(r->lchild == NULL){
    		r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
    		r->lchild->data = b;
			r->lchild->lchild = NULL;
			r->lchild->rchild = NULL;
			return 1; 
		}
		else if(r->rchild == NULL){
			r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
			r->rchild->data = b;
			r->rchild->lchild = NULL;
			r->rchild->rchild = NULL;
			return 1; 
		}
	}
	else{
		flag = STree(r->lchild,a,b);
	    if(flag != 1){
		    flag = STree(r->rchild,a,b);			
		}
	}
	return flag;
} 

int main(){
	int n,count=0;
	BiTree t;
	t = (BiTNode*)malloc(sizeof(BiTNode));
	cout<<"請建立樹:"<<endl; 
	scanf("%d",&n);
	int m=n;
	if(n!=0){
	while(n-1){
	    int a,b;
	    scanf("%d%d",&a,&b);
	    if(count == 0){
	   	    t->data = a;
	   	    t->lchild = NULL;
	   	    t->rchild = NULL;
	   	    count++;
	    }
	    STree(t,a,b);
	    n--;
	}
    }
	int p;
	scanf("%d",&p);
	LaOrderTree(t,p);
	return 0;
}

3.試編寫按層次順序遍歷二叉樹的算法

問題描述:編寫按層次順序遍歷二叉樹的算法

實驗要求:以二叉鏈表作爲存儲結構

#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
	int data;
	BiTNode *lchild,*rchild;
};
typedef BiTNode* BiTree; 

int STree(BiTree r,int a,int b){
	int flag;
	if(r == NULL) return 0;
    if(r->data == a){
    	if(r->lchild == NULL){
    		r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
    		r->lchild->data = b;
			r->lchild->lchild = NULL;
			r->lchild->rchild = NULL;
			return 1; 
		}
		else if(r->rchild == NULL){
			r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
			r->rchild->data = b;
			r->rchild->lchild = NULL;
			r->rchild->rchild = NULL;
			return 1; 
		}
	}
	else{
		flag = STree(r->lchild,a,b);
	    if(flag != 1){
		    flag = STree(r->rchild,a,b);			
		}
	}
	return flag;
} 

int count=1;
int print_level(BiTree T,int level,int k){
	if(!T || level < 0) return 0;
	if(level == 0){
		if(count!=k){
			cout<<T->data<<" ";
			count++;
		}
		else{
			cout<<T->data; 
		}
		return 1;
	}
	return print_level(T->lchild,level-1,k)+print_level(T->rchild,level-1,k);
}

void print_for_level(BiTree T,int m){
	int i=0;
	for(i=0; ;i++){
		if(!print_level(T,i,m)) break;
	}
}

int main(){
	int n,count=0;
	BiTree t;
	t = (BiTNode*)malloc(sizeof(BiTNode));
	cout<<"請建立樹:"<<endl; 
	scanf("%d",&n);
	int m=n;
	if(n!=0){
	while(n-1){
	    int a,b;
	    scanf("%d%d",&a,&b);
	    if(count == 0){
	   	    t->data = a;
	   	    t->lchild = NULL;
	   	    t->rchild = NULL;
	   	    count++;
	    }
	    STree(t,a,b);
	    n--;
	}
	}
	cout<<endl;
	cout<<"按層次遍歷結果爲"<<endl; 
	print_for_level(t,m);
	return 0;
}

4.編寫算法求二叉樹高度及寬度。

1) 問題描述:二叉樹高度是指樹中所有節點的最大層數,二叉樹寬度是指在二叉樹的各層上,具有節點數最多的那一層上的節點總數。

2) 實驗要求:以二叉鏈表作爲存儲結構

#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
	char data;
	BiTNode *lchild,*rchild;
};
typedef BiTNode *BiTree;

int STree(BiTree r,int a,int b){
	int flag;
	if(r == NULL) return 0;
    if(r->data == a){
    	if(r->lchild == NULL){
    		r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
    		r->lchild->data = b;
			r->lchild->lchild = NULL;
			r->lchild->rchild = NULL;
			return 1; 
		}
		else if(r->rchild == NULL){
			r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
			r->rchild->data = b;
			r->rchild->lchild = NULL;
			r->rchild->rchild = NULL;
			return 1; 
		}
	}
	else{
		flag = STree(r->lchild,a,b);
	    if(flag != 1){
		    flag = STree(r->rchild,a,b);			
		}
	}
	return flag;
} 

int Depth(BiTree T){
	int dep1,dep2;
	if(T == NULL) return 0;
	else{
		dep1 = Depth(T->lchild);
		dep2 = Depth(T->rchild);
		if(dep1>dep2) return(dep1 + 1);
		else return(dep2+1);
	}
} 

int Width(BiTree T){
	BiTree q[100];
	int front = -1, rear = -1;
	int flag = 0,count = 0,p;
	if(T!=NULL){
		rear++;
		q[rear] = T;   //入棧 
		flag=1;
		p=rear;
	}
	while(front<p){
		front++;
		T=q[front];
		if(T->lchild!=NULL){
			rear++;
			q[rear]=T->lchild;
			count++;
		}
		if(T->rchild!=NULL){
			rear++;
			q[rear]=T->rchild;
			count++;
		}
		if(front==p){
			if(flag<count) flag=count;
			count=0;
			p=rear;
		}
	} 
	return flag;
}
int main(){
	int n,count=0;
	BiTree t;
	t = (BiTNode*)malloc(sizeof(BiTNode));
	cout<<"請建立樹:"<<endl;
	 
	scanf("%d",&n);
	int m=n;
	if(n!=0){
	while(n-1){
	    int a,b;
	    scanf("%d%d",&a,&b);
	    if(count == 0){
	   	    t->data = a;
	   	    t->lchild = NULL;
	   	    t->rchild = NULL;
	   	    count++;
	    }
	    STree(t,a,b);
	    n--;
	}
	}
	printf("深度爲:%d 寬度爲:%d",Depth(t),Width(t));
	return 0;
}

5.實現一個哈夫曼編/譯碼系統

1)問題描述:利用哈夫曼編碼進行信息通信可以大大提高信道利用率,縮短信息傳輸時間,降低傳輸成本。但是,這要求在發送端通過一個編碼系統對待傳輸數據預先編碼,在接收端將傳來的數據進行譯碼。對於雙工信道,每端都需要一個完整的編碼/譯碼系統。試爲這樣的信息收發站寫一個哈夫曼的編/譯碼系統。

 

2)實驗要求:一個完整的系統應具有以下功能:

(1) I:初始化(Initialization)。從終端讀入字符集大小n,以及n個字符和n個權值,建立哈夫曼樹,並將它存於文件hfmTree中。

(2) E:編碼(Encoding)。利用已建好的哈夫曼樹對文件ToBeTran中的正文進行編碼,然後將結果存入文件CodeFile中。

(3) D:譯碼(Decoding)。利用已建好的哈夫曼樹將文件CodeFile中的代碼進行譯碼,結果存入文件TextFile中。

(4) P:打印代碼文件(Print)。將文件CodeFile以緊湊格式顯示在終端上,每行50個代碼。同時將此字符形式的編碼文件寫入文件CodePrin中。

(5) T:打印哈夫曼樹(Tree printing)。將已在內存中的哈夫曼樹以直觀的方式顯示在終端上,同時將此字符形式的哈夫曼樹寫入文件TreePrint中。

3) 實現提示:

(1) 文件CodeFile的基類型可以設爲字節型。

(2) 用戶界面可以設計爲“菜單”方式:顯示上述功能符號,再加上“Q”,表示退出運行Quit。請用戶鍵入一個選擇功能符。此功能執行完畢後再顯示此菜單,直至某次用戶選擇了“E”爲止。

(3) 在程序的一次執行過程中,第一次執行I、D或C命令之後,哈夫曼樹已經在內存了,不必再讀入。每次執行中不一定執行I命令,因爲文件hfmTree可能早已建好。

#include<iostream>
using namespace std;
#include<cstdlib>
#include<cstring>
#include<cmath>
#define MaxWeight 1000
#define MaxLeaf 300
#define MaxNode MaxLeaf*2-1
#define MaxBit 100
typedef struct HNodeType{
	int weight;
	int parent;
	int lchild;
	int rchild;
	char ch;
}; 
typedef struct HCodeType{
	int bit[MaxBit];
	int start;
};
typedef struct{
	HNodeType link;
	int flag;
}StackType;
int N;
void HuffmanTree(HNodeType HuTree[],int n){     //哈弗曼樹的構造 
	FILE *fp;
	int i,j,m1,m2,x1,x2;
//	scanf("%d",&n);        //輸入字符集大小
	for(i=0;i<2*n-1;i++){
		HuTree[i].weight = 0;
		HuTree[i].parent = -1;
		HuTree[i].lchild = -1;
		HuTree[i].rchild = -1;
		HuTree[i].ch = '$'; 
	}
	getchar();	
	for(i=0;i<n;i++){
		scanf("%c",&HuTree[i].ch); 
		getchar(); 
	}
	for(i=0;i<n;i++){
		scanf("%d",&HuTree[i].weight);
	}
	for(i=0;i<n-1;i++){
		m1 = m2 = MaxWeight;
		x1 = x2 = 0;
		for(j=0;j<n+i;j++){
			if(HuTree[j].weight<m1 && HuTree[j].parent == -1){
				m2 = m1;
				x2 = x1;
				m1 = HuTree[j].weight;
				x1 = j;
			}
			else if(HuTree[j].weight<m2 && HuTree[j].parent == -1){
				m2 = HuTree[j].weight;
				x2 = j;
			}
		}
		HuTree[x1].parent = n+i;
		HuTree[x2].parent = n+i;
		HuTree[n+i].weight = HuTree[x1].weight + HuTree[x2].weight;
		HuTree[n+i].lchild = x1;
		HuTree[n+i].rchild = x2;
	}
	fp=fopen("hfmTree.dat","wb");
	for(i=0;i<2*n-1;++i)
		fwrite(&HuTree[i],sizeof(HuTree),1,fp);  
		//在hfmTree中存入樹的各節點數據域信息 
	fclose(fp);
}
//編碼
void HaffmanCode(HNodeType HuTree[],int n){
	
	HCodeType HuffCode[MaxNode],cd;
	int i,j,c,p;
//	HuffmanTree(HuTree,n);
	for(i=0;i<n;i++){
		cd.start = n-1;
		c = i;
		p = HuTree[c].parent;
		while(p!=-1){
			if(HuTree[p].lchild==c) cd.bit[cd.start]=0;
			else cd.bit[cd.start]=1;
			cd.start--;
			c = p;
			p = HuTree[c].parent;
		}
		for(j=cd.start+1;j<n;j++){
			HuffCode[i].bit[j] = cd.bit[j];
		}
		HuffCode[i].start = cd.start;
	}	
	//輸出編碼 
	FILE *fp1;
	fp1 = fopen("ToBeTran.txt","r");
	FILE *fp2;
    fp2=fopen("CodeFile.txt","w");
    char b[100];
    int f=0;
	while(fscanf(fp1,"%c",&b[f]) && !feof(fp1)){
		i=0;
		while(i<n){
			if(b[f] == HuTree[i].ch){
				for(j=HuffCode[i].start+1;j<n;j++){
			        fprintf(fp2,"%ld",HuffCode[i].bit[j]);
    		    }
    		    break;
			}
			else{
				i++;
			}
		}
		f++;
	}
	fclose(fp1);
	fclose(fp2);
} 

int main(){
	HNodeType HuTree[100];
	int Q,n;
	char T;
	int p=0,c;
	char b;
    cout<<"I:初始化"<<endl;
    cout<<"E:編碼"<<endl;
    cout<<"D:譯碼"<<endl;
    cout<<"P:打印代碼文件"<<endl;
    cout<<"T:打印哈弗曼樹"<<endl;
    cout<<"Q:退出"<<endl;	
    cout<<endl; 
	cout<<"請首先建立樹:"<<endl;
	scanf("%c",&T);	

	while(T != 'Q'){
		if(T=='I'){
		
			cout<<"格式爲:節點個數 各節點名稱 各節點權值"<<endl; 
			scanf("%d",&n);
			HuffmanTree(HuTree,n);
			cout<<"建立哈弗曼樹成功!"<<endl;
			cout<<endl;
		}
		else if(T=='E'){
			HaffmanCode(HuTree,n);
			cout<<"編碼成功!"<<endl;
			cout<<endl;
		}
		else if(T=='D'){
			FILE *fp4;
	        fp4 = fopen("CodeFile.txt","r");
			FILE *fp5;
	        fp5 = fopen("TextFile.txt","w"); 
			getchar();
			while(p != -1){
				c=p;
				p = HuTree[c].parent;
			}
			int q=c;
            int count=0;
            int d=0;
			    string str;
            while(fscanf(fp4,"%c",&str[d]) && !feof(fp4)){
				if(str[d] == '0'){
					q = HuTree[q].lchild;
					if(HuTree[q].ch != '$'){
                        fprintf(fp5,"%c",HuTree[q].ch);
						q = c;
					}
				}
				else if(str[d] == '1'){
					q = HuTree[q].rchild;
					if(HuTree[q].ch != '$'){
						fprintf(fp5,"%c",HuTree[q].ch);
						q = c;	
					}
				}
				d++;
	    	}    
			cout<<"譯碼成功!"<<endl;
			cout<<endl;
		}
		
		else if(T == 'P'){
            FILE *fp8,*fp6;
            int num=100;
            char a[num];
            fp8=fopen("CodeFile.txt","r"); 
            fp6=fopen("CodePrin.txt","w"); 
            fgets(a,num,fp8);
            cout<<"打印CodeFile文件:"<<endl;
            int l= strlen(a);
            for(int j=0;j<l;j++)
            {
                cout<<a[j];
                fprintf(fp6,"%c",a[j]);
                if((j+1)%50==0)       //每行輸出50個 
                    cout<<endl;
            }
            cout<<endl;
            fclose(fp8);
            cout<<"輸出成功!"<<endl;
			cout<<endl;
		}
		else if(T == 'T'){
			FILE *fp7;
			fp7 = fopen("TreePrint.txt","w");
			int i=2*n-2,j=i+2,count=0,sum=0;
			int k=1;sum = pow(2,0);
			cout<<"哈弗曼樹爲:"<<endl; 
			while(j--){
		    	cout<<" ";
		    	fprintf(fp7,"%c",' ');
			}
		    while(i>=0){
		    	j=i;
		    	count++;
		    	cout<<HuTree[i].weight<<" "; 
		    	fprintf(fp7,"%d",HuTree[i].weight);
		    	fprintf(fp7,"%c",' ');
		    	if(count == sum){
		    		sum += pow(2,k);
		    		k++;
					cout<<endl;
					cout<<endl;
				    while(j--){
		    	    	cout<<" ";
		    	    	fprintf(fp7,"%c",' ');
				    }
				} 
				i--;
			}
			cout<<endl; 
			cout<<endl; 
			cout<<endl; 
		}
		scanf("%c",&T);
	} 
	cout<<"結束"<<endl; 
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章