数据结构上机实验

对分易作业:表的操作

算法设计作业内容:所有操作的函数头已经给出,分别写出函数体。
1)已知单链表L,设计算法求单链表的表长。 int ListLength ( LinkList L )
2)设计一个算法,求顺序表中值最大的结点的值。 int Max (SqList L )
3)设计一个算法,求单链表中值最大的结点的值。 int Max (LinkList L )
4)设计一个算法,删除数组s中的最大元素。 void DeleteMax (int s[], int n)
5)设计一个算法,删除单链表中值最大的结点。 void DeleteMax (LinkList L )
6)设计算法删除单链表L中所有值为x的结点。 void DeleteX (LinkList L, int x )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#include
#include
using namespace std;
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode,*LinkList;

//后插法 顺序相同 
void CreateList_R(LinkList &L,int n){
	L=new LNode;    //头结点 
	L->next=NULL;
	LinkList r=L;	//r为尾指针 
	for(int i=0;i>p->data;
		p->next=NULL;
		r->next=p;
		r=p;
	} 
}
//第一题 求表长度 
int ListLength(LinkList L){
	int len=0;
	LinkList p=L->next;
	while(p){
		len++;
		p=p->next;
	}
	return len;
}

//第三题 求表中最大的节点的值 
int Max(LinkList L){
	LinkList p=L->next;
	int maxnum=L->data;
	while(p){
		if(p->data>maxnum)
			maxnum=p->data;
		p=p->next;
	}
	return maxnum;
} 
//第四题 删除数组中最大元素 
void DeleteMax(int s[],int n){
	int maxid=0;
	int maxnum=s[0];
	//假设s[0]是最小的那个元素 
	for(int i=1;imaxnum){ 
			maxid=i;
			maxnum=s[i];
		} 
	}for(int i=maxid;inext;
	int maxx=p->data;
	while(p){
		if(p->data>maxx)
			maxx=p->data;
		p=p->next;
	}
	p=L;
	while(p->next){
		bool flag=false;
		if(p->next->data==maxx){
			flag=true;
			LinkList q=p->next;
			p->next=q->next;
			delete q;
		}
		if(flag)continue;
		else p=p->next;
		
	}
}
//第六题 删除单链表中所有值为x的节点 
void DeleteX(LinkList L,int x){
	LinkList p=L;
	while(p->next){
		bool flag=false;
		if(p->next->data==x){
			flag=true;
			LinkList q=p->next;
			p->next=q->next;
			delete q;
		}
		if(flag)continue;
		else p=p->next;
	}
}
int main(){
	int n;
	LinkList L;
	cin>>n;
	CreateList_R(L,n);
	//测试第一题 
	cout<next;
while(p){
		cout<data<<" ";
		p=p->next; 
	}
	cout<next;
	while(p){
		cout<data<<" ";
		p=p->next; 
	}
/*测试第四题 
	int s[4];
	for(int i=0;i<4;i++){
		cin>>s[i];
	}
	DeleteMax(s,4);
	for(int i=0;i<3;i++)cout<next=NULL;
	LinkList r;	//r为尾指针 
	int len=ListLength(L);
	cin>>r.data;
	for(int i=0;i>p->data;
		p->next=NULL;
		r->next=p;
		r=p;
	} 
}


//前插法 顺序相反 
void CreateList_H(LinkList &L,int n){
	L=new LNode;
	L->next=NULL;
	for(int i=0;i>p->data;
		p->next=L->next;
		L->next=p;
	}
}

LNode *locateElem(LinkList L,int e){
	LinkList p=L->next;
	while(p&&p->data!=e)
		p=p->next;
		return p;
}



还有一部分作业就是顺序表那部分:
#include
#include
using namespace std;
#define MAXSIZE 100
#define OVERFLOW 0
typedef struct {
	int *elem;
	int length;
}SQList;
void InitList(SQList &L){
	L.elem=new int[MAXSIZE];
	if(!L.elem)exit(OVERFLOW);
	L.length=0;
	
}
/*产生一个顺序表,先输入n,在输入n个数据,
思想就是先输入n,在输入一个数存到L.elem[0],然后比较一下顺序表中元素的
值,然后插入元素 
*/ 
void CreatList(SQList &L){
	int n,num;
	cin>>n;
	cin>>L.elem[0];
	L.length=1;
	for(int i=1;i>num;
		int j;
		for(j=1;j=j-1;k--){
					L.elem[k+1]=L.elem[k];
			}
			++L.length;
			L.elem[j]=num;
		
	}
	
}
//第二题 求顺序表中值最大的节点的值 
int MAX(SQList L){
	int maxx=L.elem[0];
	int maxid;
	for(int i=1;imaxx){
			maxid=i;
			maxx=L.elem[i];
		}
	}
	return maxid;
}
//测试函数 
int main(){
	SQList L;
	InitList(L);
	CreatList(L);
	for(int i=0;imaxx){
			maxid=i;
			maxx=L.elem[i];
		}
	}
	return maxid;
}

void ListInsert(SQList &L,int i,int e){
	if((i<1)||(i>L.length+1)) return error;
	if(L.length==MAXSIZE) return error;
	for(int j=L.length-1;j>=i-1;j--)
		L.elem[j+1]=L.elem[j];
	L.elem[i-1]=e;
	++L.length;
	return OK;
}
上机实验1(字符串链表的插入,删除,查找)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"ctype.h"
typedef struct node //定义结点
{
	char data[10]; //结点的数据域为字符串
	struct node *next; //结点的指针域
}ListNode;
typedef ListNode * LinkList; // 自定义 LinkList 单链表类型
LinkList CreatListR1(); //函数,用尾插入法建立带头结点的单链表
LinkList CreatList(void); //函数,用头插入法建立带头结点的单链表
ListNode *LocateNode(); //函数,按值查找结点
void DeleteList(); //函数,删除指定值的结点
void printlist(); //函数,打印链表中的所有值
void DeleteAll(); //函数,删除所有结点,释放内存
ListNode * AddNode(); //修改程序:增加节点。用头插法,返回头指针
//==========主函数==============
void main()
{
	char ch[10], num[5];
	LinkList head;
	head = CreatList(); //用头插入法建立单链表,返回头指针
	printlist(head); //遍历链表输出其值
	printf(" Delete node (y/n):"); //输入"y"或"n"去选择是否删除结点
	scanf("%s", num);
	if (strcmp(num, "y") == 0 || strcmp(num, "Y") == 0) {
		printf("Please input Delete_data:");
		scanf("%s", ch); //输入要删除的字符串
		DeleteList(head, ch);
		printlist(head);
	}
	printf(" Add node ? (y/n):"); //输入"y"或"n"去选择是否增加结点
	scanf("%s", num);
	if (strcmp(num, "y") == 0 || strcmp(num, "Y") == 0)
	{
		head = AddNode(head);
	}
	printlist(head);
	system("pause");
	DeleteAll(head); //删除所有结点,释放内存
}
////==========用尾插入法建立带头结点的单链表===========
//LinkList CreatListR1(void)
//{
//	char ch[10];
//	LinkList head = (LinkList)malloc(sizeof(ListNode)); //生成头结点
//	ListNode *s, *r, *pp;
//	r = head;
//	r->next = NULL;
//	printf("Input # to end "); //输入"#"代表输入结束
//	printf("\nPlease input Node_data:");
//	scanf("%s", ch); //输入各结点的字符串
//	while (strcmp(ch, "#") != 0) {
//		pp = LocateNode(head, ch); //按值查找结点,返回结点指针
//		if (pp == NULL) { //没有重复的字符串,插入到链表中
//			s = (ListNode *)malloc(sizeof(ListNode));
//			strcpy(s->data, ch);
//			r->next = s;
//			r = s;
//			r->next = NULL;
//		}
//		printf("Input # to end ");
//		printf("Please input Node_data:");
//		scanf("%s", ch);
//	}
//	return head; //返回头指针
//}

//==========用头插入法建立带头结点的单链表===========
LinkList CreatList(void)
{
	char ch[100];
	LinkList head, p;
	head = (LinkList)malloc(sizeof(ListNode));//只声明一个数据空间 
	head->next = NULL;
	while (1)
	{
		printf("Input # to end ");
		printf("Please input Node_data:");
		scanf("%s", ch);
		if (strcmp(ch, "#"))
		{
			if (LocateNode(head, ch) == NULL)//只有一个字符串 
			{
				strcpy(head->data, ch);
				p = (LinkList)malloc(sizeof(ListNode));
				p->next = head;
				head = p;//p只是一个临时的节点,并没有存到LinkList中 
			}
		}
		else
			break;
	}
	return head;
}
//==========按值查找结点,找到则返回该结点的位置,否则返回 NULL==========
ListNode *LocateNode(LinkList head, char *key)
{
	ListNode *p = head->next; //从开始结点比较
	while (p != NULL && strcmp(p->data, key) != 0) //直到 p 为 NULL 或 p->data 为 key 止
		p = p->next; //扫描下一个结点
	return p; //若 p=NULL 则查找失败,否则 p 指向找到的值为 key 的结点
}
//==========修改程序:增加节点=======
ListNode * AddNode(LinkList head)
{
	char ch[10];int pos; int i;
	ListNode *s, *pp,*p;
	printf("\nPlease input Insert_data:");
	scanf("%s", ch); //输入各结点的字符串
	printf("\nposition:");
	scanf("%d",&pos); //c语言的scanf中一定要加&,上面那个赋值给ch不用加,因为ch本身就是地质 
	pp = LocateNode(head, ch); //按值查找结点,返回结点指针
//	p = (ListNode *)malloc(sizeof(ListNode));
	p=head->next;
	
	if (pp == NULL) { //没有重复的字符串,插入到链表中
	
		s = (ListNode *)malloc(sizeof(ListNode));
		
		strcpy(s->data, ch);
		for(i=1;inext;
		
		s->next = p->next;
		p->next = s;
	
	}
	
	return head;
}
//==========删除带头结点的单链表中的指定结点=======
void DeleteList(LinkList head, char *key)
{
	ListNode *p, *r, *q = head;
	p = LocateNode(head, key); //按 key 值查找结点的
	if (p == NULL) { //若没有找到结点,退出
		printf("position error");
		exit(0);
	}
	while (q->next != p) //p 为要删除的结点,q 为 p 的前结点
		q = q->next;
	r = q->next;
	q->next = r->next;
	free(r); //释放结点
}
//===========打印链表=======
void printlist(LinkList head)
{
	ListNode *p = head->next; //从开始结点打印
	while (p) {
		if(p->next==NULL)printf("%s", p->data);
		else printf("%s, ", p->data);
		p = p->next;
	}
	printf("\n");
}
//==========删除所有结点,释放空间===========
void DeleteAll(LinkList head)
{
	ListNode *p = head, *r;
	while (p->next) {
		r = p->next;
		free(p);
		p = r;
	}
	free(p);
}

/*1,首先明白了头插法和尾插法的区别:头插法是从一个表开始,重复读入数据,
生成新节点,将读入数据存放到新节点的数据域中,
然后将新节点插入到当前链表的头结点之后,直至读入结束标志为止。
其插入的顺序和存储的逻辑顺序相反,而尾插法相同。
2,在按值查找这个函数中,要返回指定值的节点,
可以这么写:while (p != NULL && strcmp(p->data, key) != 0)p = p->next;
这样的话,当程序跳出while循环之后,p就只要求的节点(p为NULL说明链表中没有该值的节点)。
3,在打印链表的时候while()中要写p而不是p->next,
否则的话最后一个节点就打印不出来了;
在删除所有节点的函数中,while函数中写的是p->next,而不是p,
这样的话,p走到最后一个节点的时候就不会进入while循环了,
那么在while循环外面还要写free(p)来删除最后那个节点
*/

上机实验二 实验二:顺序表的基本操作

实验目的:
1、理解什么是顺序表;
2、掌握顺序表的基本操作,如建立、查找、插入和删除等。
实验内容:
定义一个包含学生信息(学号,姓名,成绩)的顺序表,使其具有如下功能:
(1) 根据指定学生个数,逐个输入学生信息;
(2) 逐个显示学生表中所有学生的相关信息;
(3) 根据姓名进行查找,返回此学生的学号和成绩;
(4) 根据指定的位置可返回相应的学生信息(学号,姓名,成绩);
(5) 给定一个学生信息,插入到表中指定的位置;
(6) 删除指定位置的学生记录;
(7) 统计表中学生个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

#include  
#include  
#include  
#include  
#define OK 1  
#define ERROR 0  
#define OVERFLOW -2  
#define MAXSIZE 100  
  
typedef int Status; // 定义函数返回值类型  
  
typedef struct  
{  
    char num[10]; // 学号  
    char name[20]; // 姓名  
    double grade; // 成绩   
}student;  
  
typedef student ElemType;  
  
typedef struct  
{  
    ElemType *elem; // 存储空间的基地址   
    int length; // 当前长度   
}SqList;  
  
Status InitList(SqList *L) // 构造空的顺序表 L   
{     
    L->elem=(ElemType *)malloc(sizeof(ElemType)*MAXSIZE);  
    if(!L->elem)  exit(OVERFLOW);  
    L->length=0;  
    return OK;  
}  
  
ElemType GetElem(SqList &L,int i) // 访问顺序表,找到 i位置,返回给 e  
{  
    return L.elem[i];  
}  
  
int Search(SqList &L,char str[]) // 根据名字查找,返回该同学在顺序表中的编号   
{  
    for(int i=1;i<=L.length;i++)  
    {  
        if(strcmp(L.elem[i].name,str)==0)  
            return i;  
    }  
    return 0;  
}  
  
Status ListInsert(SqList &L,int i,ElemType e) // 在 i位置插入某个学生的信息   
{  
    if((i<1)||(i>L.length+1)) return ERROR;  
    if(L.length==MAXSIZE)   return ERROR;  
    for(int j=L.length;j>=i;j--)  
    {  
        L.elem[j+1]=L.elem[j];  
    }  
    L.elem[i]=e;  
    ++L.length;  
    return OK;  
}  
  
Status ListDelete(SqList &L,int i) // 在顺序表中删除 i位置的学生信息   
{  
    if((i<1)||(i>L.length))   return ERROR;  
    for(int j=i;j<=L.length;j++)  
    {  
        L.elem[j]=L.elem[j+1];  
    }  
    --L.length;  
    return OK;  
}  
  
void Input(ElemType *e)  
{  
    printf("姓名:");  scanf("%s",e->name);  
    printf("学号:");  scanf("%s",e->num);  
    printf("成绩:");  scanf("%lf",&e->grade);  
    printf("输入完成\n\n");  
}  
  
void Output(ElemType *e)  
{  

	printf("\t%s\t%s\t%f\n",e->name,e->num,e->grade);  
}  
  
int main()  
{  
    SqList L;  
    ElemType a,b,c,d;  
    printf("\n********************************\n\n");  
    puts("1. 构造顺序表");   
    puts("2. 录入学生信息");  
    puts("3. 显示学生信息");  
    puts("4. 输入姓名,查找该学生");  
    puts("5. 显示某位置该学生信息");   
    puts("6. 在指定位置插入学生信息");  
    puts("7. 在指定位置删除学生信息");  
    puts("8. 统计学生个数");  
    puts("0. 退出");  
    printf("\n********************************\n\n");  
    int x,choose;  
    while(1)  
    {  
        puts("请选择:");  
        scanf("%d",&choose);  
        if(choose==0)   break;  
        switch(choose)  
        {  
            case 1:  
                    if(InitList(&L))  
                        printf("成功建立顺序表\n\n");  
                    else  
                        printf("顺序表建立失败\n\n");  
                    break;  
            case 2:  
                    printf("请输入要录入学生的人数(小于100):");  
                    scanf("%d",&x);  
                    for(int i=1;i<=x;i++)  
                    {  
                        printf("第%d个学生:\n",i);  
                        Input(&L.elem[i]);  
                    }  
                    L.length=x;  
                    puts("");  
                    break;  
            case 3:  
                    printf("\t姓名\t学号\t成绩\n");
				    for(int i=1;i<=x;i++)  
                    {  
                        a=GetElem(L,i);  
                        Output(&a);  
                    }  
                    break;  
            case 4:  
                    char s[20];  
                    printf("请输入要查找的学生姓名:");  
                    scanf("%s",s);  
                    if(Search(L,s))  
                        Output(&L.elem[Search(L,s)]);  
                    else  
                        puts("对不起,查无此人");  
                    puts("");  
                    break;  
			case 5:  
				printf("请输入要查询的位置:");    
				int id1;                   
				scanf("%d",&id1);  
				if((id1<1)||(id1>L.length+1)) {
					puts("要查询的位置不合法");
					continue;
				}   
				b=GetElem(L,id1);           
				Output(&b);       
				break;
            case 6:  
                    printf ("请输入要插入的位置:");  
                    int id2;  
                    scanf("%d",&id2);  
                    printf("请输入学生信息:\n");  
                    Input(&c);  
                    if(ListInsert(L,id2,c))  
                    {  
                        x++;  
                        puts("插入成功");  
                        puts("");  
                    }  
                    else  
                    {  
                        puts("插入失败");  
                        puts("");     
                    }  
                    break;  
            case 7:  
                    printf("请输入要删除的位置:");  
                    int id3;  
                    scanf("%d",&id3);  
                    if(ListDelete(L,id3))  
                    {  
                        x--;  
                        puts("删除成功");  
                        puts("");  
                    }  
                    else  
                    {  
                        puts("删除失败");  
                        puts("");     
                    }  
                    break;  
            case 8:  
                    printf("已录入的学生个数为:%d\n\n",L.length);  
                    break;  
        }  
    }  
    printf("\n\n谢谢您的使用,请按任意键退出\n\n\n");  
    system("pause");  
    return 0;  
}  

/* 
预习报告
1.	按学生的姓名来查找学生信息时,声明一个sceach的函数判断一下顺序表中
是否有该同学,如果存在,那么返回该同学在顺序表中的位置k,然后output函数返
回第k个位置的学生信息;如果不存在,就输出信息提示没有该同学。

预习报告代码:
int Search(SqList &L,char str[]) // 根据名字查找,返回该同学在顺序表中的编号   
{  
    for(int i=1;i<=L.length;i++)  
    {  
        if(strcmp(L.elem[i].name,str)==0)  
            return i;  
    }  
    return 0;  
}  
 
2.	删除的顺序应该先声明一个用来计数的变量,该变量的值从第i个元素开始,
依次加1,直到j大于表长度,让每个变量对应存储的值向前移动,实现删除第i个元素的功能 
实现for循环
 for(int j=i;j<=L.length;j++)  
    {  
        L.elem[j]=L.elem[j+1];  
    }  

3.在指定位置插入元素,实现ListInsert函数,把顺序表,id2(要插入的位置),
c(包含一个学生的信息的student类型的结构体变量),该函数应该判断插入的位置id2是否合法,
然后在id2以后的所有已经存在的结构题变量往后一一个位置,
空出要插入的位置,插入要插入的位置,表长加1。如果插入成功返回1,否则放那会0.

4.要查询指定位置的学生信息时,首先把顺序表和指定位置i当作参数,实现GetElem的方法,
让该方法返回指定位置的学生信息。

实验心得
1.	程序的健壮性是指程序能对输入的非法数据进行处理,并不会因为输入非法数据导致程序的崩溃。
写程序要考虑程序的健壮性,比如本次实验在ListDelete这个方法中要对传进来的参数i(要插入的位置)进行判断,
如果插入的位置小于1或者大于表长度+1,就提示输入数据有误。
2.	为了方便阅读,书写程序要有层次的缩进,这样一眼就能看出来每个语句块的内容,方便理解 
3.	Input函数中,那个向传过来的参数e赋值grade语句时,一定要加&,因为name和num都是引用型数据,
可以不加&。
4.	switch语句,要在每个case语句中加入break语句,否则的话,执行完一条case语句,
就会接着执行下一跳语句。可以在if语句之后写continue和break,但满足if条件时,就执行该语句,跳过循环或者退出循环 

5.	删除指定位置的元素时,该方法首先要判断删除的位置是否合法,
然后从第i个位置到最后一个元素依次往前移动,覆盖要删除的位置,表长减1.

6.	Output(&a);这一条语句调用output函数要加&来运行,因为原函数当中是ElemType *e当作形参的,
那个a是student类型的,&a就代表这个参数为指向student类型的地址。
*/

上机实验三 栈

一、实验目的
熟悉栈的顺序表示与实现。
熟悉栈的应用。
理解并掌握递归函数的设计与实现。
二、实验内容
1 问题描述:利用栈实现十进制数n转化为d(分别是2,8,16)进制数
要求:
输入一个n和d,打印输出d进制数序列。
利用顺序栈来实现十进制数n转化为其他d进制数。此时,需要同时实现初始化空栈、入栈、出栈、判栈空等辅助功能。
测试数据:
8进制:输入n:1348 输出:2504
2进制:输入n:1348 输出:101 0100 0100‬
16进制:输入n:1348 输出:544

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include 
#include 
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */ 
#define STACK_INCREMENT 2 /* 存储空间分配增量 */ 
#define TRUE 1 
#define FALSE 0 
#define OK 1 
#define ERROR 0 
#define OVERFLOW 0 
typedef struct SqStack {
 	int *base; 
 	/* 在栈构造之前和销毁之后,base 的值为 NULL */ 
	int *top; /* 栈顶指针 */ 
 	int stacksize; /* 当前已分配的存储空间,以元素为单位 */ 
 	//整个sqStack的大小是24,所以base,top和stacksize各为8 
 }SqStack; /* 顺序栈 */ 
 
 void InitStack(SqStack *s) { 
 /* 构造一个空栈 S */ 
 	s->base=(int *)malloc(STACK_INIT_SIZE*sizeof(int)); 
 	if(!s->base) exit(OVERFLOW); /* 存储分配失败 */ 
	s->top=s->base; 
 	s->stacksize=STACK_INIT_SIZE; 
 } 
 
 int StackEmpty(SqStack s) { 
 /* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */ 
	 if(s.top==s.base) return TRUE; 
	 else return FALSE; 
 } 
 
 int StackLength(SqStack s) { 
 
	 /* 返回 S 的元素个数,即栈的长度 */ 
 	return s.top-s.base; 
 } 
 
 void Push(SqStack *s,int e) { 
 /* 插入元素 e 为新的栈顶元素 */ 
	 if(s->top-s->base>=s->stacksize) //这两个相等的时候重新分配内存 
 /* 栈满,追加存储空间 */ 
 	{ 
 		s->base=(int *)realloc(s->base,(s->stacksize+STACK_INCREMENT)*sizeof(int)); 
 		//每次开辟两个空间,下一次让top指针指向刚stacksisze的位置,然后s->top++之后也不会溢出 
		 if(!s->base) exit(1); 
 /* 存储分配失败 */ 
 		s->top=s->base+s->stacksize; //s->stacksize这个是原来没改变之前的那个
		 //是为了让top指针指向刚刚大一size之后的第一个位置; 
		s->stacksize+=STACK_INCREMENT; 
	} 
	*(s->top)++=e;   //这是数值和数值的赋值,*(s->top)是指向这个地址的数值 
} 

int Pop(SqStack *s,int *e) { 
/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则 返回 ERROR */ 
	if(s->top==s->base) return ERROR; 
	*e=*--s->top; 
	return OK;
 } 
 

 void conversion_16() { 
 /* 对于输入的任意一个非负 10 进制整数,打印输出与其等值的 16 进制数 */ 
 	SqStack s; int n; /* 非负整数 */ 
 	int e; InitStack(&s); /* 初始化栈 */ 
 	printf("将 10 进制整数 n 转换为 16 进制数\n 请输入 n( >0 ):"); 
 	scanf("%d",&n); /* 输入非负十进制整数 n */ 
 	while(n){/* 当 n 不等于 0 */
 		 Push(&s,n%16); /* 入栈 n 除以 16 的余数(16 进制的低位) */ 
 		 n=n/16; 
	  } 
  	while(!StackEmpty(s)) /* 当栈不空 */ 
  	{ 
  		Pop(&s,&e); /* 弹出栈顶元素且赋值给 e */ 
 		 if(e<=9) printf("%d",e); 
 		 else printf("%c",e+55); /* 大于 9 的余数,输出相应的字符*/ 
 	 } 
	printf("\n");
}  


 void conversion_8() { 
 /* 对于输入的任意一个非负 10 进制整数,打印输出与其等值的 8 进制数 */ 
 	SqStack s; int n; /* 非负整数 */ 
 	int e; InitStack(&s); /* 初始化栈 */ 
 	printf("将 10 进制整数 n 转换为 8 进制数\n 请输入 n( >0 ):"); 
 	scanf("%d",&n); /* 输入非负十进制整数 n */ 
 	while(n){/* 当 n 不等于 0 */
 		 Push(&s,n%8); /* 入栈 n 除以 8 的余数(8 进制的低位) */ 
 		 n=n/8; 
	  } 
  	while(!StackEmpty(s)) /* 当栈不空 */ 
  	{ 
  		Pop(&s,&e); /* 弹出栈顶元素且赋值给 e */ 
 		 printf("%d",e);
 	 } 
	printf("\n");
}  

void conversion_2() { 
 /* 对于输入的任意一个非负 10 进制整数,打印输出与其等值的 2进制数 */ 
 	SqStack s; int n; /* 非负整数 */ 
 	int e; InitStack(&s); /* 初始化栈 */ 
 	printf("将 10 进制整数 n 转换为 2 进制数\n 请输入 n( >0 ):"); 
 	scanf("%d",&n); /* 输入非负十进制整数 n */ 
 	while(n){/* 当 n 不等于 0 */
 		 Push(&s,n%2); /* 入栈 n 除以 2 的余数(2 进制的低位) */ 
 		 n=n/2; 
	  } 
  	while(!StackEmpty(s)) /* 当栈不空 */ 
  	{ 
  		Pop(&s,&e); /* 弹出栈顶元素且赋值给 e */ 
 		 printf("%d",e);
 	 } 
	printf("\n");
}  


 	 
  int main() { 
  
  SqStack s; int n; /* 非负整数 */ 
 	int e; InitStack(&s); /* 初始化栈 */ 
// 	Push(&s,3);
// 	Push(&s,4);	Push(&s,4);
 	printf("%d",s.stacksize); //ans是10
	 	printf("%d",sizeof(s));  //ans24
 	
 	
 	
 	
 	
//  int choice;
//   printf("%s","1.十进制转二进制\n");
//  	  printf("%s","2.十进制转八进制\n");
//  	  printf("%s","3.十进制转十六进制\n");
//  while(1){
//  	 
//  	  printf("%s","请输入序号:");
//	  scanf("%d",&choice);
//	  switch(choice){
//	  	case 1: conversion_2(); break;
//	  	case 2: conversion_8();break;
//	  	case 3: conversion_16();break;
//	  	default: return 0;
//	  } 
// 	 } 
  } 
  
  
  /* 
  	预习报告 
  	1.进制转换可以使用顺序栈这种数据结构,SqStack 结构包括两个int
	类型的指针,top和base,还保存着顺序栈的存储空间的大小。
其结构体定义如下: 
	typedef struct SqStack {
 		int *base; 
		int *top; 
 		int stacksize;  
 	}SqStack; 
  		2.栈是一种只在表尾进行插入或者删除的操作的线性表,表尾
	  叫栈顶(本题中的top指针),表头端称为栈底(本题中的base指针);栈的修改是按照后进先出的原则
	  进行的。本题目正好符合进制转换中先得到的余数后输出,即先得到的余数
	  是低位,可以用栈这种数据结构来实现。 
  	3.ASCII表中A对应的十进制数为65,9对应的十进制数为57,若对
	  16取余的余数大于9,则可用余数+55得到其相应字母对应的10进制数
	  然后将该十进制数转换为相应的字符,这种方法实现了10进制转换为相应的16进制数。
	4.5.八进制转换 
 	 void conversion_8() { 
 	/* 对于输入的任意一个非负 10 进制整数,打印输出与其等值的 8 进制数 */ 
// 	SqStack s; int n; /* 非负整数 */ 
// 	int e; InitStack(&s); /* 初始化栈 */ 
// 	printf("将 10 进制整数 n 转换为 8 进制数\n 请输入 n( >0 ):"); 
// 	scanf("%d",&n); /* 输入非负十进制整数 n */ 
// 	while(n){/* 当 n 不等于 0 */
// 		 Push(&s,n%8); /* 入栈 n 除以 8 的余数(8 进制的低位) */ 
// 		 n=n/8; 
//	  } 
//  	while(!StackEmpty(s)) /* 当栈不空 */ 
//  	{ 
//  		Pop(&s,&e); /* 弹出栈顶元素且赋值给 e */ 
// 		 printf("%d",e);
// 	 } 
//	printf("\n");
//}
	
	
	/* 
	心得 
		1.对于输入一个任意的非负十进制整数n,对n除以16结果为a,余数为b,
	将余数b压入顺序栈,继续对a进行此操作,直至a为0;
	当栈不为空时,弹出相应的数输出即可;对于16进制输出,首先判断弹出的元素e
	是否小于9,若大于9输出(e+55)对应的字符即可 。 
	
	2. 根据问题的要求,利用顺序栈实现将十进制数n转换为 16,2,8进制数, 
	此时 同时要实现初始化空栈,入栈,出栈,判栈空,栈的长度等功能。
	其中:判断栈空的条件是栈顶指针和栈底指针相等。栈的长度是 栈顶指针和栈底指针的差值
	。
	 
	3.在栈顶插入元素,即入栈操作 ,首先是先判断栈是否已满,如果栈满就realloc
	函数重新为栈分配新的空间, 初始化栈顶到没扩展之前的base+stacksize的位置 
	
  */

上机实验四 实验题目:循环队列基本操作 循环队列基本操作

【 实验目的 】
1、 掌握用 VC 工具上机调试循环队列的基本方法;
2、 掌握循环队列的基本操作,循环队列初始化、入队、出队、判断队空、判断队满
以及求队列长度操作;
3、 掌握队列的先进先出运算规则及其在病人看病模拟程序中的应用,理解队列在运算过程
中状态的变化。
【 实验要求 】

  1. 循环队列的初始化、入队、出队、判断是否为空、求队列长度及队列输出操作的实现;
  2. 编写程序模拟实现病人看病排队。
    【 需求分析 】
    1、 程序应该达到的功能:
    在病人排队看医生的过程中,主要重复两件事:
    (1) 病人到达诊室,将病历本交给护士,排到等待队列中候诊;
    (2) 护士从等待队列中取出下一位病人的病历,该病人进入诊室就诊。
    要求程序能够模拟病人等待就诊这一过程,因此程序应采取菜单方式,且各选项的功能
    如下:
    (1) 排队——输入排队病人的病历号,加入病人排队队列中;
    (2) 就诊——病人排队队列中最前面的病人就诊,并将其从队列中删除;
    (3) 查看队列——从队首到队尾依次列出所有的排队病人的病历号;
    (4) 不再接受排队,队列中现有病人依次就诊。
    (5) 下班——退出系统。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include 
#include 
typedef int ElementType;
#define MaxSize 5
// 队列结构体定义
typedef struct {
	ElementType patient[MaxSize];
	int front, rear;
} Queue;
// 排队(入队)
void AddQ(Queue *PtrQ) {
	int flag = 0, i, item;
	i = PtrQ->front;//第一次加的时候,i指向front初始值为0 
	if( (PtrQ->rear+1)%MaxSize == PtrQ->front ) {//判断队满了没有 
		printf(" >>排队人数已超出范围, 请先诊断病人.\n");
		return;
	}
	do {
		scanf("%d", &item);
		while((i++)%MaxSize != PtrQ->rear ) {
			//如果只有两个的话,++i之后就会直接不运行下面这个while了 
		//这地方不能改为++i,为什么呀,font队头本身就不用判断呀,因为有时候要 
			if(item == PtrQ->patient[i%MaxSize]) {//i修改为i%MaxSize,因为i++之后有可能会跳过一些数 
				
				flag = 1;
				break;
			} else
				flag = 0;
		}
		if( flag == 1 ) {
			printf(" >>病历号重复, 请重新输入:");
			i = PtrQ->front;//重新跟新一下i,新加上的 
		}
	} while( flag );
	PtrQ->rear = (PtrQ->rear+1) % MaxSize;
	PtrQ->patient[PtrQ->rear] = item;//没与下一行调换顺序 ,为了让在0的位置存一下数据 ?? 
	
	
	return;
}
// 就诊(出队)
void Treatment(Queue *PtrQ) {
	int patient;
	if( PtrQ->front == PtrQ->rear ) {//不要+1 ,相等就是队满了 
		printf(" >>没人在排队看病.\n");
		return;
	} else {
		
		 
		PtrQ->front = (PtrQ->front+1) % MaxSize;
		patient = PtrQ->patient[PtrQ->front];
		printf(" >>病人%d 就诊\n", patient);
		
		
		return;
	}
}
// 查看排队情况(遍历循环队列)
void print(Queue *PtrQ) {
	int i = PtrQ->front;//头部指向数据的前一个没有数据的节点 
	if( PtrQ->front == PtrQ->rear ) {
		printf(" >>没有人在排队.\n");
		return;
	} else {
		printf(" >>排队的人有:");
		while( (i % MaxSize) != PtrQ->rear) {
		//while中i修改为(i % MaxSize)  
		//如果i是队尾了,就不用输出了,因为队尾在上一次就已经输出来了 
			printf("%d ", PtrQ->patient[(i+1)%MaxSize]);//i+1修改为 (i+1)%MaxSize
			//最开始的时候从下标为1的头开始读取 
			i++;
		}
		printf("\n");
	}
	return;
}
// 余下依次就诊,不再排队(遍历队列)
void NoMoreQueue(Queue *PtrQ) {
	int i;
	if(PtrQ->front == PtrQ->rear) {
		printf(" >>没有排队的人.\n");
		return;
	} else {
		i = PtrQ->front;
		printf(" >>病人按以下顺序就诊:");
		while( i%MaxSize != PtrQ->rear ) {
			printf("%d ", PtrQ->patient[(i+1)%MaxSize]);
			//第一次就输出队头的下一个元素 ,i+1修改为 (i+1)%MaxSize 
			
			i++;
			PtrQ->front = (PtrQ->front+1) % MaxSize;
		}
		printf("\n");
	}
	return;
}


int main() {
	int flag = 1, sel;
	Queue *p;
	p = (Queue *)malloc(sizeof(Queue));
	p->front = 0;
	p->rear = 0;
	while( flag ) {
		printf("1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:");
		scanf("%d", &sel);
		switch( sel ) {
			case 1 :
				printf(" >>请输入病历号:");
				AddQ( p );
				break;
			case 2 :
				Treatment( p );
				break;
			case 3 :
				print( p );
				break;
			case 4 :
				NoMoreQueue( p );
				break;
			case 5 :
				if(p->front != p->rear )
					printf(" >>请排队的病人明天就医!现在要下班了\n");
				else
					printf(" >>已经没有排队的病人,现在准备下班!\n");
				flag = 0;
				break;
		}
	}
	return 0;
}

/*1:

bug1:那个不再排队直接一次就诊之后还要不要能看那个查看排队
bug2:为什么在排队时第一次输入一个重复的病历单后,之后输入
不同的病历单也会出现病历单重复的信息,而且程序会直接会崩 



 预习报告:
 1.余下的一次就诊的方法设计思路:首先是判断一下队列的头指针和尾指针是否相同,相同的话队列
为空,就显示没有正在排队的人,否则,声明一个临时变量i,让它指向队列的头部, printf("%d ", PtrQ->patient[i+1]);
因为i+1 有可能比5要大,不对 MaxSize取模的话就会出现显示未知数据的情况,所以应该这样写:printf("%d ", PtrQ->patient[(i+1)%MaxSize]);
 并且应该在i++之后写PtrQ->front = (PtrQ->front+1) % MaxSize;,这样的话每一个病人就诊完后,头指针+1(将该病人从队列中删除),
 这样的话选择4之后就还可以选择1,再添加病人。 
 
 2. 入队操作的设计思路,应该先判断队列是否已满,已满的话就提示信息;否则获取要排队的
 序号,与此同时对队列中已有的序号与输入的序号进行比较,如果相同就提示再次输入
 ,然后队列尾指针向后移动一位,在尾指针处存入相应的数据,头部指针是不存储数据的。
 
 实验心得: 
1. 在AddQ方法中判断输入的序号是否出现时,while(i++!=PtrQ->rear) 
该条语句应该改为 while((i++)%MaxSize != PtrQ->rear )
并且本条语句if(item == PtrQ->patient[i]) 也应该 改为if(item == PtrQ->patient[i%MaxSize]) 
否则会因为在while语句中i++后i的值比原来增加1,少比较一些值,会出现在队列中加入
与原来相同的序号
2.在NoMoreQueue方法中,printf("%d ", PtrQ->patient[i+1]);也会出现显示相同序号的问题,
printf("%d ", PtrQ->patient[(i+1)%MaxSize]);
	同样在print方法中, printf("%d ", PtrQ->patient[i+1]);该条语句的后果可能会出现
	两个相同的序号,但是在选择2挨个就诊的时候并不会出现两个相同的序号 ,所以该条语句应改为
printf("%d ", PtrQ->patient[(i+1)%MaxSize]);

	
	
	
实验结果	
	1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:1
 >>请输入病历号:1
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:1
 >>请输入病历号:2
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:1
 >>请输入病历号:3
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:1
 >>请输入病历号:4
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:3
 >>排队的人有:1 2 3 4
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:2
 >>病人1 就诊
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:2
 >>病人2 就诊
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:1
 >>请输入病历号:1
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:4
 >>病人按以下顺序就诊:3 4 1
1:排队 2:就诊 3:查看排队 4.不再排队,余下依次就诊 5:下班请选择:5
 >>已经没有排队的病人,现在准备下班!

 */

上机实验五 二叉树

一、实验目的
   1.掌握二叉树树的结构及非线性特点,递归特点和动态性。
   2.巩固对指针的使用和二叉树的三种遍历方法、建立方法。
二、实验内容
   二叉树的实现和运算

预习报告:

  1. 首先是树的节点的声明
    typedef struct BitNode {
    //节点存放char类型的数据
    char data;
    //声明两个节点类型的左指针和右指针
    struct BitNode lchild,rchild;
    }*BitTree;

  2. 先序建立二叉树BinTreeCreat的方法,首先本算法要在叶子结点下
    输入#来代表下面没有节点了,所以先获取输入节点的值,如果该节点
    的值为#,那么该节点的子树为空,如果该节点的值不为#,那么
    递归的建立左子树右子树。

  3. 先序遍历二叉树BinTraverse方法,首先应该判断输入的树是否为
    不为空就输出该节点的值,递归的输出左子树和右子树的值

  4. 求二叉树的深度BinTreeDepth函数的设计思路为:首先声明一个
    int类型的变量depthval,判断二叉树是否为空,不为空就
    递归的调用该方法求左子树右子树的深度,求完的时候还要
    在 depthLeft和depthRight中求最大值还要+1,该结果就是
    二叉树的深度。

  5. 求二叉树中所有结点数的BinTreeCount方法,首先要声明int
    类型的变量node,和求二叉树的深度的函数的设计方法相似,
    判断二叉树是否为空,不为空就递归的调用该方法求左子树右
    子树的节点,最后总的节点数为左子树+右子树+1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
实验代码:
#include 
#include 
using namespace std;
typedef char DataType;
typedef struct BitNode {
	DataType data;
	struct BitNode *lchild,*rchild;
}*BitTree;
void BinTreeInit(BitTree &BT) { // 初始化二叉树,即把树根指针置空
	BT=(BitTree)malloc(sizeof(BitNode));
	BT->data=NULL;
	cout<<" 二叉树初始化成功 !"<>ch;
	if(ch=='#') BT=NULL;
	else {
		if(!(BT=(BitTree)malloc(sizeof(BitNode))))
			exit(0);
		BT->data=ch;
		BinTreeCreat(BT->lchild);
		BinTreeCreat(BT->rchild);
	}
	return 0;
}
void BinTreeEmpty(BitTree &BT) { // 检查二叉树是否为空
	if(BT->data==NULL)
		cout<<" 是空二叉树 !"<data;
		BinTraverse(BT->lchild);
		BinTraverse(BT->rchild);
	}
}
int BinTreeDepth(BitTree BT) { // 求二叉树的深度
	int depthval;
	if(BT){
		int depthLeft=BinTreeDepth(BT->lchild);
		int depthRight=BinTreeDepth(BT->rchild);
		depthval = 1+(depthLeft>depthRight?depthLeft:depthRight);
	} else depthval=0;
	return depthval;
}
int BinTreeCount(BitTree BT) { // 求二叉树中所有结点数
	int node;
	if(BT) {
		int lchild=BinTreeCount(BT->lchild);
		int rchild=BinTreeCount(BT->rchild);
		node=lchild+rchild+1;
	} else node= 0;
	return node;
}
int main() {
	int i;
	BitTree BT;
	cout<<"1 、初始化二叉树 :"<<"\n2 、按先序序列建立二叉树 "<<"\n3 、判断二叉树是否为空 :";
	cout<<"\n4 、先序序列遍历二叉树 "<<"\n5 、求二叉树的深度 "<<"\n6 、求二叉树节点的个数 "<>i;
		if(i==1)
			BinTreeInit(BT);
		else if(i==2) {
			cout<<" 输入你要建立的二叉树 :"<

上机实验六 实验题目 : 图的 存储与遍历

实验目的 :
掌握有向图和无向图的概念;掌握邻接矩阵和邻接链表建立图的存储结构;掌握 DFS 及
BFS 对图的遍历操作。
实验要求:
采用邻接矩阵作为图的存储结构,完成有向图和无向图的 DFS 和 BFS 操作。
实验主要步骤:
设计一个有向图和一个无向图,任选一种存储结构,完成有向图和无向图的 DFS(深度优
先遍历)和 BFS(广度优先遍历)的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include"stdio.h"
#include"stdlib.h"
#define MaxVertexNum 100
//定义最大顶点数
typedef struct {
	char vexs[MaxVertexNum];
	//顶点表
	int edges[MaxVertexNum][MaxVertexNum];
	//邻接矩阵,可看作边表
	int n,e;
	//图中的顶点数 n 和边数 e

} MGraph;

//用邻接矩阵表示的图的类型
//=========建立邻接矩阵=======
void CreatMGraph(MGraph *G) {
	int i,j,k;
	char a;
	printf("Input VertexNum(n) and EdgesNum(e): ");
	scanf("%d,%d",&G->n,&G->e);
	//输入顶点数和边数
	scanf("%c",&a);

	printf("Input Vertex string:");

	for(i=0; in; i++)         {
		scanf("%c",&a);
		G->vexs[i]=a;
		//读入顶点信息,建立顶点表

	}
	for(i=0; in; i++)
		for(j=0; jn; j++)
			G->edges[i][j]=0;
	//初始化邻接矩阵
	printf("Input edges,Creat Adjacency Matrix\n");
	for(k=0; ke; k++) {
		//读入 e 条边,建立邻接矩阵
		scanf("%d%d",&i,&j);
		//输入边(Vi,Vj)的顶点序号
		G->edges[i][j]=1;

		G->edges[j][i]=1;
		//若为无向图,矩阵为对称矩阵;若建立有向图,去掉该条语句
	}
} //=========定义标志向量,为全局变量=======
typedef enum {FALSE,TRUE} Boolean;

Boolean visited[MaxVertexNum];
//========DFS:深度优先遍历的递归算法======
void DFSM(MGraph *G,int i) {
//以 Vi 为出发点对邻接矩阵表示的图 G 进行 DFS 搜索,邻接矩阵是 0,1 矩阵
	int j;
	printf("%c",G->vexs[i]);
	//访问顶点 Vi


	visited[i]=TRUE;
	//置已访问标志
	for(j=0; jn; j++)
		//依次搜索 Vi 的邻接点
		if(G->edges[i][j]==1 && ! visited[j])      DFSM(G,j);
	//(Vi,Vj)∈E,且 Vj 未访问过,故 Vj 为新出发点
}
void DFS(MGraph *G) {
	int i;
	for(i=0; in; i++)
		visited[i]=FALSE;
	//标志向量初始化
	for(i=0; in; i++)  if(!visited[i])
			//Vi 未访问过

			DFSM(G,i);
	//以 Vi 为源点开始 DFS 搜索
}
//===========BFS:广度优先遍历=======
void BFS(MGraph *G,int k) {
	//以 Vk 为源点对用邻接矩阵表示的图 G 进行广度优先搜索
	int i,j,f=0,r=0;
	int cq[MaxVertexNum];
	//定义队列

	for(i=0; in; i++)  visited[i]=FALSE;
	//标志向量初始化

	for(i=0; in; i++)  cq[i]=-1;
	//队列初始化
	printf("%c",G->vexs[k]);
	//访问源点 Vk
	visited[k]=TRUE;


	cq[r]=k;
	//Vk 已访问,将其入队。注意,实际上是将其序号入队
	while(cq[f]!=-1) {
		//队非空则执行
		i=cq[f];
		f=f+1;             //Vf 出队
		for(j=0; jn; j++)       //依次 Vi 的邻接点 Vj
			if(G->edges[i][j]==1 && !visited[j]) {  //Vj 未访问
				printf("%c",G->vexs[j]);         //访问 Vj
				visited[j]=TRUE;
				r=r+1;
				cq[r]=j;
				//访问过 Vj 入队
			}
	}
} //==========main=====
int main() {
	int i;
	MGraph *G;
	G=(MGraph *)malloc(sizeof(MGraph));
	//为图 G 申请内存空间

	CreatMGraph(G);
	//建立邻接矩阵
	printf("Print Graph DFS: ");
	DFS(G);
	//深度优先遍历
	printf("\n");
	printf("Print Graph BFS: ");
	BFS(G,3);
	//以序号为 3 的顶点开始广度优先遍历
	printf("\n");
	system("pause");
	return 0;
}
/* 
实验结果: 
Input VertexNum(n) and EdgesNum(e): 8,9
Input Vertex string:01234567
Input edges,Creat Adjacency Matrix
0 1
0 2
1 3
1 4
2 5
2 6
3 7
4 7
5 6
Print Graph DFS: 01374256
Print Graph BFS: 31704256
 
 预习报告:
 	1,在树形结构中,数据元素之间有着明显的层次关系,并且每一层
	 中和上一层中的元素可能和下一层中的多个元素相关;而在图的
	 结构中,节点之间的关系可以是任意的,图中任意两个数据元素之间
	 都有可能相关。
	2. 关于图的一些基本术语,邻接点:对于无向图G,如果图的边(v,v')
	 属于E,那么顶点v,v'互为邻接点。
	 路径:从一个顶点到另一个顶点的顶点序列叫做路径。
	 路径长度:是一条路径上经过的边或弧的数目。
	 连通:在无向图中,两个顶点之间存在路径,就说这两个顶点是连通的。
	 
	 
实验心得:
	1.深度优先搜索遍历类似于数的先序遍历,是树的先序遍历的推广。	  
	本实验中:首先进行标志向量初始化,对没有访问过的节点进行
	DFS搜索,对于顶点vi进行搜索时,先输出本节点的值,在输出与本节点
	的邻接点。这样就对整个图进行了搜索。
	2.广度优先搜索遍历类似于数的按层次遍历的过程,设x和y是来给你个相继
	被访问的顶点,若当前是以x为出发点进行搜索,则在访问x的所有未曾访问
	过的领节点之后,紧接着是以y为出发点进行横向搜索;
	3.本此实验中用到的是邻接矩阵,骑士表示是顶点之间相邻关系的矩阵,
	用他表示图,可以很容易的通过邻接矩阵的值来判断两个顶点之间是否有边
	也很容易的计算各个顶点的度。 
*/

上机实验七 题目: 顺序查找与二分查找

【 实验目的 】
本次实习的主要目的在于熟悉顺序表和有序表的查找方法和特点。其中以熟悉各种顺序表的
操作为侧重点。通过本次实习还可帮助读者复习高级语言的使用方法。
【实验要求】
【问题描述】
①建立一个查找表,使用顺序查找算法对其元素进行查找,并输出查找时比较的元素和最
终的比较的次数。如果没有找到,则把该元素插入到该查找表中。
②建立一个有序查找表,使用二分查找算法对其元素进行查找,并输出查找时比较的元素
和最终的比较的次数;如果没有找到,则把该元素插入到该查找表中。
【基本要求】
查找过程中,同时输出查找时比较的元素和最终的比较的次数,当没有找到元素时输出
“没有此元素”,然后把该元素插入到该查找表中;否则输出此元素在查找表中的位置。
【测试数据】
1、查找表中的元素{1,5,7,2,8,9,6,0,4,3},查找元素为 8,查找元素 10。
2、查找表中的元素{0,1,2,3,4,5,6,7,8,9},查找元素为 8,查找元素 10。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#include
#include
#include
#include 		// exit()函数包含在此头文件中 
#define LIST_INIT_SIZE 100 // 初始化大小
#define LISTINCREMENT 15
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
#define MT(a,b) ((a)>(b))
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 0
typedef int ElemType;	 // 基本(元素)类型
typedef struct {
	ElemType * elem;
	int length;
	int listsize;
} SSTable;
int InitTable(SSTable *L)
// 操作结果:构造一个空的顺序线性表
{
	(*L).elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
	if(!(*L).elem) // 存储分配失败
		exit(OVERFLOW);
	(*L).length=0; // 空表长度为 0
	(*L).listsize=LIST_INIT_SIZE; // 初始存储容量
	return OK;
}
int TableInsert(SSTable *L,int i,ElemType e)
// 初始条件:顺序线性表 L 已存在,1≤i≤ListLength(L)+1 。操作结果:在 L 中第 i 个位置
//之前插入新的数据元素 e,L 的长度加 1
{
	ElemType *newbase,*q,*p;
	if(i<1||i>(*L).length+1) // i 值不合法
		return ERROR;
	if((*L).length>=(*L).listsize) { // 当前存储空间已满,增加分配
		newbase=(ElemType
		         *)realloc((*L).elem,((*L).listsize+LISTINCREMENT)*sizeof(ElemType));
		if(!newbase) // 存储分配失败
			exit(OVERFLOW);
		(*L).elem=newbase; // 新基址
		(*L).listsize+=LISTINCREMENT; // 增加存储容量
	}
	q=(*L).elem+i-1; // q 为插入位置
	for(p=(*L).elem+(*L).length-1; p>=q; --p) // 插入位置及之后的元素右移
		*(p+1)=*p;
	*q=e; // 插入 e
	++(*L).length; // 表长增 1
	return OK;
}
int Search_Seq(SSTable ST,ElemType key) {
//在顺序表 ST 中顺序查找其关键字等于 key 的数据元素。若找到,则函数值为该元素
	//在表中的位置,否则为 0。
	int i,j,k=0;
	for(i=ST.length-1; !EQ(ST.elem[i],key)&&i>=0; --i) { //从后往前找,因为啥??不从头忘后找呀
		k++;
		printf("比较的元素为:%d\n",ST.elem[i]);
	}
	if(!EQ(ST.elem[i],key)) {
		//这句话就是在for循环比较完了之后在判断
		//一下,如果表中没有这个key就添加进去,
		//否则就输出比较的次数
		printf("查找该元素,比较的次数为:%d\n",k);
		j=TableInsert(&ST,ST.length+1,key);
		return 1;
	} else {
		k++;
		printf("比较的元素为:%d\n",ST.elem[i]);
		printf("查找该元素,比较的次数为:%d\n",k);
		return 0;
	}
}
int Search_Bin(SSTable ST,ElemType key) {
//在有序表 ST 中折半查找其他关键字等于 key 的数据元素。若找到,则函数值为该元
	//素在表中的位置,否则为 0。
	int low,high,mid,j,k=0;
	low=0;
	high=ST.length-1; //置区间初值
	while(low<=high) {
		mid=(low+high)/2;
		if(EQ(key,ST.elem[mid])) {
			k++;
			printf("比较的元素为:%d\n",ST.elem[mid]);
			printf("查找该元素,比较的次数为:%d\n",k); //找到待查元素
			return 0;
		} else if(LT(key,ST.elem[mid])) {
			k++;
			printf("比较的元素为:%d\n",ST.elem[mid]);
			high=mid-1; //继续在前半区间进行查找
		} else if(MT(key,ST.elem[mid])) {
			k++;
			printf("比较的元素为:%d\n",ST.elem[mid]);
			low=mid+1;
		}
	}
	if(!EQ(key,ST.elem[mid])) {
		printf("查找该元素,比较的次数为:%d\n",k);//没有找到待查元素
		if(LT(key,ST.elem[mid]))
			j=TableInsert(&ST,mid+1,key);
		else if(MT(key,ST.elem[mid]))
			j=TableInsert(&ST,ST.length+1,key);
	}
	return 1;
}
int Menu() {
	int choice;
	printf("************************\n");
	printf(" 1.新建静态查找表\n");
	printf(" 2.输出静态查找表\n");
	printf(" 3.顺序查找\n");
	printf(" 4.二分查找查找\n");
	printf(" 5.退出\n");
	printf("============================\n");
	printf("请选择:");
	scanf("%d", &choice);
	return choice;
}
void print(ElemType *c) {
	printf("%d ",*c);
}
int main() {
	SSTable L;
	int i,j,k,m,n,ch;
	while (ch!=5) {
		ch=Menu();
		switch(ch) {
			case 1:
				printf("请输入表 L 的元素个数 n 的值:");
				scanf("%d",&n);
				InitTable(&L); // 创建空表 L 成功
				printf("请输入顺序表 L 的%d 个元素(格式为:元素 1 元素 2):\n",n);
				for(j=1; j<=n; j++) { // 在表 L 中插入 n 个元素
					scanf("%d",&k);
					i=TableInsert(&L,j,k);
				}
				break;
			case 2:
				printf("顺序表 L 的元素分别为:"); // 输出表 L 的内容
				for(i=0; i

实验题目: 内部排序

【 实验目的 】
1. 掌握常见的排序算法的思想及其适用条件。
2. 掌握常见的排序算法的程序实现。
【实验要求】
输入一组关键字序列分别实现下列排序: :

    1. 实现直接插入排序、折半插入排序和希尔排序算法。 实现直接插入排序、折半插入排序和希尔排序算法。
    1. 实现 实现 快速排序算法。
    1. 实现归并排序算法。 实现归并排序算法。
    1. 在主函数中设计一个简单的菜单,分别测试上述算法。 在主函数中设计一个简单的菜单,分别测试上述算法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#include
#include
#include
#include
#include
#include
#include "iostream"
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status;
typedef int Boolean;
//对两个数值型关键字的比较
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
//待排记录的数据类型
#define MAXSIZE 20 //一个用作示例的小顺序表的最大长度
typedef int KeyType; //定义关键字类型为整型
typedef int InfoType; //定义其它数据项的类型
typedef struct {
	KeyType key; //关键字项
	InfoType otherinfo;//其他数据项
} RedType; //记录类型
typedef struct {
	RedType r[MAXSIZE+1];//r[0]闲置或用作哨兵单元
	int length;//顺序表长度
} SqList; //顺序表类型
typedef SqList HeapType; // 堆采用顺序表存储表示
//顺序表插入排序的函数
void InsertSort(SqList &L);
void BInsertSort(SqList &L);
void ShellInsert(SqList &L,int dk);
void ShellSort(SqList &L,int dlta[],int t);
//快速排序
int Partition(SqList &L,int low,int high);
void QSort(SqList &L,int low,int high);
void QuickSort(SqList &L);
//归并排序
void Merge(RedType SR[],RedType TR[],int i,int m,int n);
void MSort(RedType SR[],RedType TR1[],int s, int t);
void MergeSort(SqList &L);
//输出函数
void print(SqList L);
#define N 8
#define T 3
using namespace std;
int main() {
	RedType d[N]= {{20,6},{52,1},{65,3},{88,9},{47,8},{22,4},{39,5},{74,7}};
	int i;
	SqList LL;
	int dt[T]= {5,3,1}; // 增量序列数组
	int choice;
s123:
	cout<<"请选择要使用的排序算法:\n0..............退出\n";
	cout<<"1..............插入排序\n2..............交换排序\n";
	cout<<"3..............归并排序\n";
	cin>>choice;
	switch(choice) {
		case 0:
			break;
		case 1: //插入排序
			for(i=0; i=high+1; --j)
			L.r[j+1]=L.r[j];
		L.r[high+1]=L.r[0];
	}//for
}

//希尔排序 
void ShellInsert(SqList &L,int dk) {
	//对顺序表 L 作一趟希尔插入排序。本算法是和一趟直接插入排序相比,作了以下修改:
// 1.前后记录位置的增量是 dk,而不是 1;
// 2.r[0]只是暂存单元,不是哨兵。当 j<=0 时,插入位置已找到。
	int i,j;
	for(i=dk+1; i<=L.length; ++i)
		if LT(L.r[i].key,L.r[i-dk].key) {
			//需将 L.r[i]插入有序增量子表
			L.r[0]=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]; //记录后移,查找插入位置
			L.r[j+dk]=L.r[0]; //插入
		}
}
void ShellSort(SqList &L,int dlta[],int t) {
	//按增量序列 dlta[0..t-1]对顺序表 L 作希尔排序。
	int k;
	for(k=0; k=pivotkey)
			--high;
		L.r[low]=L.r[high]; //将比枢轴记录小的记录移到低端
		while(low

你可能感兴趣的:(数据结构上机实验)