当前位置:   article > 正文

c语言数据结构课程设计_关于计算器数据结构课程设计

关于计算器数据结构课程设计

  正文

一.概述

1.本次数据结构所做5个题目:

 11.2.1一元稀疏多项式计算器

 11.2.5模拟浏览器操作系统  

 11.2.10图的基本操作与实现

  11.2.18八皇后问题

   11.2.21木棒加工问题

2.使用语言:

C语言

3.编译环境:

Dev-C++;Microsoft Visual C++ 6.0

二.课程设计题目

1.一元稀疏多项式计算器

1.1问题描述

    设计一个一元稀疏多项式简单计算器。

1.2需求分析
  1.  输入并建立多项式。
  2. 输出多项式,输出形式为整数序列:n.c1.e1,c2,e2,....cn,en,其中    n是多项式的项数,ci,ei,分别是第i项的系数和指数,序列按指数降序排序。

         (4)实现多项式 a和 b 相加,建立多项式 a+b。

         (5)实现多项式 a和 b相减,建立多项式 a—b。

         (6)计算多项式在×处的值。

         (7)计算器的仿真界面

1.3算法的设计与实现

1.3.1设计思路
1. 输入并建立多项式:
   - 用户输入多项式的项数n。
   - 循环n次,每次输入一个项的系数ci和指数ei。
   - 将所有输入的项保存在一个列表中。
2. 输出多项式:
   - 对保存的多项式进行按指数降序排序。
   - 遍历排序后的多项式列表,依次输出每个项的系数和指数。
3. 多项式相加:
   - 用户输入两个多项式a和b。
   - 创建一个空的结果多项式c。
   - 遍历a和b的项,将对应指数相同的项的系数相加,并将结果添加到c中。
   - 如果某个多项式的项已经遍历完,将另一个多项式剩余的项直接添加到c中。
4. 多项式相减:
   - 用户输入两个多项式a和b。
   - 创建一个空的结果多项式c。
   - 遍历a和b的项,将对应指数相同的项的系数相减,并将结果添加到c中。
   - 如果某个多项式的项已经遍历完,将另一个多项式剩余的项取相反数后直接添加到c中。
5. 计算多项式在×处的值:
   - 用户输入一个值x。
   - 遍历多项式的每个项,将每个项的系数乘以x的指数次幂,并累加得到结果。
6. 计算器的仿真界面:
   - 可以使用图形用户界面(GUI)库来实现计算器的界面。
   - 在界面上提供输入框和按钮,用于输入多项式、操作符和值。
   - 根据用户的选择,调用相应的函数进行计算,并在界面上显示结果。

 1.3.2主要函数说明与源程序代码

主要函数:

dnode *creat()            //用链表存放多项式

void swap(dnode *p,dnode *q)            /*交换p,q指针所指的指数和系数*/

void sort(dnode *h)                        /*采用冒泡法对链表每一项重新排序*/

dnode *operate(dnode *a,dnode *b)        /*稀疏多项式计算*/

void prn(dnode *h)//打印结果

float qiuzhi(int x,dnode *h)  //求多项式在x处的值

 源代码:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<malloc.h>
  4. #define NULL 0
  5. typedef struct node /*定义多项式每一项*/
  6. {
  7. int e; //e为指数
  8. float c; //c为系数
  9. struct node *next; //next指向下一项
  10. }dnode;
  11. dnode *creat() /*用链表存放多项式*/
  12. { //多项式的创建, 即输入两个多项式
  13. dnode *h,*p;
  14. int e,i,n; //n为多项式的项数
  15. float c; //c为多项式的系数
  16. h=(dnode *)malloc(sizeof(dnode)); //分配头节点
  17. h->next=NULL;
  18. do //当n为0或小于1时,则重新输入
  19. {
  20. printf("请输入多项式的项数n:");
  21. scanf("%d",&n);
  22. }while(n<1);
  23. for(i=1;i<=n;i++) //输入各项的系数c和指数e
  24. {
  25. printf("请输入第%d项的系数c和指数e:",i);
  26. scanf("%f%d",&c,&e);
  27. p=(dnode *)malloc(sizeof(dnode)); //创建新结点
  28. p->c=c;p->e=e; //将值传给data域
  29. p->next=h->next;//用头插法建立链表
  30. h->next=p;
  31. }
  32. return h; //返回头结点
  33. }
  34. void swap(dnode *p,dnode *q) /*交换p,q指针所指的指数和系数*/
  35. {
  36. float m; //中间变量
  37. int n; //中间变量
  38. n=p->e; //交换操作
  39. p->e=q->e;
  40. q->e=n;
  41. m=p->c;
  42. p->c=q->c;
  43. q->c=m;
  44. }
  45. void sort(dnode *h) /*采用冒泡法对链表每一项重新排序*/
  46. {
  47. dnode *pi,*pl,*p,*q;
  48. p=h->next; //p此时指向第一项
  49. while(p->next!=NULL)
  50. p=p->next; //寻找尾结点
  51. pi=p; //pi指向最后一次交换的位置,初值为表尾
  52. while(pi!=h->next) //结点数大于1时
  53. {
  54. pl=h->next; //为中间变量,起传递地地址的作用
  55. for(p=h->next;p!=pi;p=p->next)
  56. {
  57. q=p->next;
  58. if(p->e>q->e)
  59. {
  60. swap(p,q); //调用交换函数
  61. pl=p;
  62. }
  63. }
  64. pi=pl; //pi指向前一个结点
  65. }
  66. }
  67. dnode *operate(dnode *a,dnode *b) /*稀疏多项式计算*/
  68. {
  69. int sel;
  70. float x;
  71. dnode *p1,*p2,*p,*t; //t为结果链表的表头
  72. t=(dnode *)malloc(sizeof(dnode));
  73. t->next=NULL;
  74. printf("--------------------------------------\n");
  75. printf("| 请选择运算方式: |\n");
  76. printf("| 1、多项式相加 |\n");
  77. printf("| 2、多项式相减 |\n");
  78. printf("| 0、退出! |\n");
  79. printf("--------------------------------------\n");
  80. printf("请选择:");
  81. scanf("%d",&sel);
  82. p1=a->next;
  83. p2=b->next;
  84. while(p1&&p2)
  85. {
  86. if(p1->e==p2->e) //指数相同
  87. {
  88. if(sel==1)
  89. x=p1->c+p2->c; //系数相加
  90. else
  91. x=p1->c-p2->c; //系数相减
  92. if(x!=0)
  93. {
  94. p=(dnode *)malloc(sizeof(dnode));
  95. p->e=p1->e;
  96. p->c=x;
  97. p->next=t->next;//利用头插法将p结点插入t中
  98. t->next=p;
  99. }
  100. p1=p1->next;
  101. p2=p2->next;
  102. }
  103. else if(p1->e>p2->e) //p1的指数大于p2的指数
  104. {
  105. p=(dnode *)malloc(sizeof(dnode));
  106. p->e=p2->e;
  107. if(sel==1)
  108. p->c=p2->c;
  109. else
  110. p->c=(-1)*p2->c;
  111. p->next=t->next;
  112. t->next=p;
  113. p2=p2->next;
  114. }
  115. else //p1的指数小于p2的指数
  116. {
  117. p=(dnode *)malloc(sizeof(dnode));
  118. p->e=p1->e;
  119. p->c=p1->c;
  120. p->next=t->next;
  121. t->next=p;
  122. p1=p1->next;
  123. }
  124. }
  125. while(p1!=NULL) //p2为空,p1不为空时
  126. {
  127. p=(dnode *)malloc(sizeof(dnode));
  128. p=p1;
  129. p1=p1->next;
  130. p->next=t->next; //把p1 放在结果链表后面
  131. t->next=p;
  132. }
  133. while(p2!=NULL) //p1为空,p2不为空时
  134. {
  135. p=(dnode *)malloc(sizeof(dnode));
  136. p->e=p2->e;
  137. if(sel==2) //如果选择的是2,则将p2中剩余的项的系数取其相反数
  138. p->c=(-1)*p2->c;
  139. else
  140. p->c=p2->c;
  141. p2=p2->next;
  142. p->next=t->next; //把p1 放在结果链表后面
  143. t->next=p;
  144. }
  145. return t; //返回运算后的多项式的头结点
  146. }
  147. void prn(dnode *h)//打印结果
  148. {
  149. dnode *p;
  150. p=h->next;
  151. if(p==NULL) //如果多项式项数为0
  152. {
  153. printf("多项式项数为0,退出!\n");
  154. exit(0);
  155. }
  156. printf("生成的多项式如下:\n");
  157. while((p->next)!=NULL) //否则,则输出
  158. {
  159. printf("%3.1f X^%d + ",p->c,p->e);
  160. p=p->next;
  161. }
  162. if(p->next==NULL)
  163. {
  164. printf("%3.1f X^%d\n",p->c,p->e);
  165. }
  166. }
  167. float qiuzhi(int x,dnode *h) //求多项式在x处的值
  168. {
  169. dnode *p;
  170. float sum=0;
  171. int i,t;
  172. printf("请输入x的值:");
  173. scanf("%d",&x);
  174. for(p=h->next;p;p=p->next)
  175. {
  176. t=1;
  177. for(i=p->e;i!=0;)
  178. {
  179. if(i<0){t/=x;i++;}//指数小于0,进行除法
  180. else{t*=x;i--;} //指数小于0,进行除法
  181. }
  182. sum+=p->c*t;
  183. }
  184. return sum;
  185. }
  186. void main()
  187. {
  188. int x;
  189. float sum=0;
  190. dnode *a,*b,*c;
  191. a=creat(); //第一个多项式
  192. sort(a); //排序
  193. prn(a); //打印结果
  194. b=creat(); //第二个多项式
  195. sort(b); //排序
  196. prn(b); //打印结果
  197. c=operate(a,b); //结果多项式
  198. prn(c); //打印
  199. sum=qiuzhi(x,c);
  200. printf("多项式的值为:%.3f",sum);
  201. printf("\n");
  202. }

1.4 调试分析与测试结果
   1.4.1.调试:

【问题一】
- 输入错误:用户输入的多项式格式不正确,例如指数为负数或非整数,系数为非数字等。

解决办法:添加通俗易懂的文字提醒用户输入

【问题二】

   编译环境有问题

    解决办法:换一个编译器

   1.4.2测试结果:

2.模拟浏览器操作程序

2.1问题描述

        标准Web浏览器具有在最近访问的网页间后退和前进的功能。实现这些功能的一个方法是:使用两个栈,追踪可以后退和前进而能够到达的网页。在本题中,要求模拟实现这一功能。

2.2需求分析

 需要支持以下指令:

BACK:将当前页推到“前进栈”的顶部。取出“后退栈”中顶端的页面,使它成为当前页。若“后退栈”是空的,忽略该命令。

FORWARD:将当前页推到“后退栈”的顶部。取出“前进栈”中顶部的页面,使它成为当前页。如果“前进栈”是空的,忽略该命令。

VISIT <url>:将当前页推到“后退栈”的顶部。使 URL特指当前页。清空“前进栈”。

QUIT:退出浏览器。

假设浏览器首先加载的网页 URL 是:

2.3算法的设计与实现

        2.3.1设计思路

          运用了栈,“先进后出,后进先出”的特点。BACK,FORWARD操作对应的进行栈的进出。此外,还设置了标志位flag判断是否退出,将num与栈的长度进行比较,确定输出网址还是ignore。

       2.3.2主要函数说明

    void PUSHQ(QU *qu, char cur[ ])//入队

void POPQ(QU *qu)//出队

void PUSH(ST *st, char cur[])//入栈

void POP(ST *st)//出栈

int EMPTY(ST *st)//判空

void BACK(ST *stfront,ST *strear,char cur[], QU *qu)//回溯

void FORWARD(ST *stfront, ST *strear, char cur[], QU *qu)//前寻

void VISIT(ST *stfront,ST *strear, char cur[],QU *qu)//访问

  【源程序】

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. typedef struct stack
  5. {
  6. char s[100][70];
  7. int top;
  8. }ST;//栈定义
  9. typedef struct queue
  10. {
  11. char q[100][70];
  12. int head;
  13. int tail;
  14. }QU;//队列定义,用于接受输出
  15. void PUSHQ(QU *qu, char cur[])//入队
  16. {
  17. if (qu->tail == 100)
  18. {
  19. printf("队满\n");
  20. }
  21. else
  22. {
  23. qu->tail++;
  24. strncpy(qu->q[qu->tail], cur,strlen(cur) + 1);
  25. }
  26. }
  27. void POPQ(QU *qu)//出队
  28. {
  29. qu->head++;
  30. }
  31. void PUSH(ST *st, char cur[])//入栈
  32. {
  33. if (st->top == 100)
  34. {
  35. printf("栈满\n");
  36. }
  37. else
  38. {
  39. strncpy(st->s[st->top],cur,strlen(cur)+1);
  40. st->top++;
  41. }
  42. }
  43. void POP(ST *st)//出栈
  44. {
  45. if (st->top == 0)
  46. {
  47. printf("栈空\n");
  48. }
  49. else
  50. {
  51. st->top--;
  52. }
  53. }
  54. int EMPTY(ST *st)//判空
  55. {
  56. if (st->top == 0)
  57. return 1;
  58. else
  59. return 0;
  60. }
  61. void BACK(ST *stfront,ST *strear,char cur[], QU *qu)//回溯
  62. {
  63. if (!EMPTY(strear))
  64. {
  65. PUSH(stfront, cur);
  66. POP(strear);
  67. strncpy(cur,strear->s[strear->top],strlen(strear->s[strear->top]) + 1);
  68. PUSHQ(qu, cur);
  69. }
  70. else
  71. {
  72. char *a = "Ignored";
  73. PUSHQ(qu, a);
  74. }
  75. }
  76. void FORWARD(ST *stfront, ST *strear, char cur[], QU *qu)//前寻
  77. {
  78. if (!EMPTY(stfront))
  79. {
  80. PUSH(strear, cur);
  81. POP(stfront);
  82. strncpy(cur, stfront->s[stfront->top],strlen(stfront->s[stfront->top]) + 1);
  83. PUSHQ(qu, cur);
  84. }
  85. else
  86. {
  87. char *a = "Ignored";
  88. PUSHQ(qu,a);
  89. }
  90. }
  91. void VISIT(ST *stfront,ST *strear, char cur[],QU *qu)//访问
  92. {
  93. PUSHQ(qu, cur);
  94. stfront->top = 0;
  95. }
  96. int main()
  97. {
  98. printf("输入:\n");
  99. ST stfront;
  100. ST strear;
  101. stfront.top = 0;
  102. strear.top = 0;
  103. QU qu;
  104. qu.head = -1;
  105. qu.tail = -1;
  106. char cur[70];
  107. char start[70] = "http://www.acm.org/";//需先对此网站进行如回溯栈的特殊处理
  108. char in[2][70];
  109. strncpy(cur, start,strlen(start) + 1);
  110. scanf("%s", in[0], 70);
  111. while (strcmp(in[0], "QUIT") != 0)
  112. {
  113. if (strcmp(in[0], "VISIT") == 0)
  114. {
  115. PUSH(&strear, cur);
  116. scanf("%s", in[1], 70);
  117. strncpy(cur,in[1],strlen(in[1])+1);
  118. VISIT(&stfront, &strear, cur, &qu);
  119. }
  120. else if (strcmp(in[0], "QUIT") == 0)
  121. {
  122. break;
  123. }
  124. else if (strcmp(in[0], "BACK") == 0)
  125. {
  126. BACK(&stfront, &strear, cur, &qu);
  127. }
  128. else
  129. {
  130. FORWARD(&stfront, &strear, cur, &qu);
  131. }
  132. scanf("%s", in[0], 70);
  133. }
  134. printf("输出:\n");//输出
  135. while (qu.head != qu.tail)
  136. {
  137. POPQ(&qu);
  138. printf("%s\n", qu.q[qu.head]);
  139. }
  140. return 0;
  141. }

2.4调试分析与结果测试

  2.4.1调试分析:


   后退栈为空时执行BACK指令:
   - 当用户执行BACK指令时,程序应检查后退栈是否为空。
   - 如果后退栈为空,则无法执行BACK指令,程序应忽略该命令。
   - 当用户执行FORWARD指令时,程序应检查前进栈是否为空。
   - 如果前进栈为空,则无法执行FORWARD指令,程序应忽略该命令。
  执行VISIT指令:
   - 当用户执行VISIT指令时,程序应将当前页推到后退栈的顶部。
   - 如果指定的URL与当前页相同,则不进行任何操作。
   - 程序应清空前进栈,以确保用户在执行其他操作时无法前进到已访问的页面。
 执行QUIT指令:
   - 当用户执行QUIT指令时,程序应退出浏览器。
 初始加载网页URL:
   - 浏览器首次加载网页URL为

http://www.acm.org/。
   - 程序应将此URL作为当前页,并将其推入后退栈的顶部。


  2.4.2测试结果

   

3.图的基本操作与实现

3.1问题描述

         要求用邻接表存储结构,实现对图 11-3 所示的有向带权网络 G 的操作。

3.2需求分析

 (1)输入含 n(1≤n≤100)个顶点(用字符表示顶点)和e条边。

(2)求每个顶点的出度和人度,输出结果。

(3)指定任意顶点×为初始顶点,对图G作DFS遍历,输出 DFS 顶点序列。

(4)指定任意顶点x为初始顶点,对图G作BFS 遍历,输出 BFS 顶点序列。

(5)输入顶点 x,查找图 G:若存在含x 的顶点,则删除该结点及与之相关联的边,并作 DFS遍历;否则输出信息“无x”。

(6)判断图 G是否是连通图,输出信息“YES”/“NO”。

(7)根据图 G 的邻接表创建图 G 的邻接矩阵,即复制图G。

(8)找出该图的一棵最小生成树。

3.3算法设计与实现

3.3.1设计思路

1. 创建一个图的类,包含顶点和边的数据结构和操作方法。
2. 定义一个函数,接受输入的顶点和边的数量,并创建对应数量的顶点和边。
3. 定义函数来计算每个顶点的出度和入度,并输出结果。
4. 定义DFS遍历函数,接受初始顶点作为参数,使用递归或者栈来实现深度优先搜索,并输出DFS顶点序列。
5. 定义BFS遍历函数,接受初始顶点作为参数,使用队列来实现广度优先搜索,并输出BFS顶点序列。
6. 定义函数来接受输入的顶点x,并查找图G中与之相关联的顶点和边。如果存在顶点x,则删除该顶点及与之相关联的边,并进行DFS遍历;否则输出"无x"。
7. 定义函数来判断图G是否是连通图。使用DFS或BFS遍历,检查是否可以遍历到所有的顶点。如果可以,则输出"YES";否则输出"NO"。
8. 定义函数来根据图G的邻接表创建邻接矩阵,并复制图G。
9. 定义函数来找出图的一棵最小生成树。使用Prim算法或Kruskal算法来实现。

3.3.2主要函数说明及源程序

   

  1. //有向带权图,邻接表中的节点
  2. typedef struct Node {
  3. int value;//顶点下标,也可以说是值
  4. int weight;//权
  5. struct Node* next;//指针域
  6. } Node;
  7. // 图的结构
  8. typedef struct Graph {
  9. int numNodes;//节点数
  10. Node** adjacencyList;
  11. } Graph;
  12. // 创建节点
  13. Node* createNode(int value, int weight) {
  14. Node* newNode = (Node*)malloc(sizeof(Node));
  15. newNode->value = value;
  16. newNode->weight = weight;
  17. newNode->next = NULL;
  18. return newNode;
  19. }
  20. // 创建图,传入节点数
  21. Graph* createGraph(int numNodes) {
  22. Graph* graph = (Graph*)malloc(sizeof(Graph));
  23. graph->numNodes = numNodes;
  24. graph->adjacencyList = (Node**)malloc(numNodes * sizeof(Node*));
  25. // 初始化邻接表为空
  26. for (int i = 0; i < numNodes; i++) {
  27. graph->adjacencyList[i] = NULL;
  28. }
  29. return graph;
  30. }
  31. // 添加边
  32. void addEdge(Graph* graph, int source, int target, int weight) {
  33. // 创建新的节点
  34. Node* newNode = createNode(target, weight);
  35. // 将新节点插入到源节点的邻接表中,顶点以下标为标准直接以头插法插入
  36. newNode->next = graph->adjacencyList[source];
  37. graph->adjacencyList[source] = newNode;
  38. }
  39. // 求顶点的出度
  40. int outDegree(Graph* graph, int vertex) {
  41. Node* currentNode = graph->adjacencyList[vertex];
  42. int outDegree = 0;
  43. while (currentNode != NULL) {
  44. outDegree++;
  45. currentNode = currentNode->next;
  46. }
  47. return outDegree;
  48. }
  49. // 求顶点的入度,遍历整个邻接表
  50. int inDegree(Graph* graph, int vertex) {
  51. int inDegree = 0;
  52. for (int i = 0; i < graph->numNodes; i++) {
  53. Node* currentNode = graph->adjacencyList[i];
  54. while (currentNode != NULL) {
  55. if (currentNode->value == vertex) {
  56. inDegree++;
  57. }
  58. currentNode = currentNode->next;
  59. }
  60. }
  61. return inDegree;
  62. }
  63. // 深度优先,递归遍历
  64. void DFS(Graph* graph, int vertex, int* visited) {
  65. visited[vertex] = 1;
  66. printf("%d ", vertex);
  67. Node* currentNode = graph->adjacencyList[vertex];
  68. while (currentNode != NULL) {
  69. int neighbor = currentNode->value;
  70. if (!visited[neighbor]) {
  71. DFS(graph, neighbor, visited);
  72. }//如果此顶点未被访问,则继续深度优先遍历
  73. currentNode = currentNode->next;
  74. }
  75. }
  76. // 广度优先遍历
  77. void BFS(Graph* graph, int startVertex) {
  78. int* visited = (int*)malloc(graph->numNodes * sizeof(int));
  79. for (int i = 0; i < graph->numNodes; i++) {
  80. visited[i] = 0;
  81. }
  82. // 创建队列
  83. int* queue = (int*)malloc(graph->numNodes * sizeof(int));
  84. int front = 0;
  85. int rear = 0;
  86. visited[startVertex] = 1;
  87. printf("%d ", startVertex);
  88. queue[rear++] = startVertex;
  89. while (front < rear) {
  90. int vertex = queue[front++];
  91. Node* currentNode = graph->adjacencyList[vertex];
  92. while (currentNode != NULL) {
  93. int neighbor = currentNode->value;
  94. if (!visited[neighbor]) {
  95. visited[neighbor] = 1;
  96. printf("%d ", neighbor);
  97. queue[rear++] = neighbor;
  98. }
  99. currentNode = currentNode->next;
  100. }
  101. }
  102. free(visited);
  103. free(queue);
  104. }
  105. // 查找顶点
  106. bool searchVertex(Graph* graph, int vertex) {
  107. for (int i = 0; i < graph->numNodes; i++) {
  108. Node* currentNode = graph->adjacencyList[i];
  109. while (currentNode != NULL) {
  110. if (currentNode->value == vertex) {
  111. return true;
  112. }
  113. currentNode = currentNode->next;
  114. }
  115. }
  116. return false;
  117. }
  118. // 判断是否为连通图
  119. bool isConnected(Graph* graph) {
  120. int* visited = (int*)malloc(graph->numNodes * sizeof(int));
  121. for (int i = 0; i < graph->numNodes; i++) {
  122. visited[i] = 0;
  123. }
  124. DFS(graph, 0, visited);
  125. for (int i = 0; i < graph->numNodes; i++) {
  126. if (visited[i] == 0) {
  127. free(visited);
  128. return false;
  129. }
  130. }
  131. free(visited);
  132. return true;
  133. }
  134. // 创建邻接矩阵
  135. int** createAdjacencyMatrix(Graph* graph) {
  136. int** matrix = (int**)malloc(graph->numNodes * sizeof(int*));
  137. for (int i = 0; i < graph->numNodes; i++) {
  138. matrix[i] = (int*)malloc(graph->numNodes * sizeof(int));
  139. for (int j = 0; j < graph->numNodes; j++) {
  140. matrix[i][j] = 0;
  141. }
  142. }
  143. for (int i = 0; i < graph->numNodes; i++) {
  144. Node* currentNode = graph->adjacencyList[i];
  145. while (currentNode != NULL) {
  146. matrix[i][currentNode->value] = currentNode->weight;
  147. currentNode = currentNode->next;
  148. }
  149. }
  150. return matrix;
  151. }
  152. 【源程序】
  153. #include <stdio.h>
  154. #include <stdlib.h>
  155. #include <stdbool.h>
  156. //有向带权图
  157. // 邻接表中的节点
  158. typedef struct Node {
  159. int value;//顶点下标,也可以说是值
  160. int weight;//权
  161. struct Node* next;//指针域
  162. } Node;
  163. // 图的结构
  164. typedef struct Graph {
  165. int numNodes;//节点数
  166. Node** adjacencyList;
  167. } Graph;
  168. // 创建节点
  169. Node* createNode(int value, int weight) {
  170. Node* newNode = (Node*)malloc(sizeof(Node));
  171. newNode->value = value;
  172. newNode->weight = weight;
  173. newNode->next = NULL;
  174. return newNode;
  175. }
  176. // 创建图,传入节点数
  177. Graph* createGraph(int numNodes) {
  178. Graph* graph = (Graph*)malloc(sizeof(Graph));
  179. graph->numNodes = numNodes;
  180. graph->adjacencyList = (Node**)malloc(numNodes * sizeof(Node*));
  181. // 初始化邻接表为空
  182. for (int i = 0; i < numNodes; i++) {
  183. graph->adjacencyList[i] = NULL;
  184. }
  185. return graph;
  186. }
  187. // 添加边
  188. void addEdge(Graph* graph, int source, int target, int weight) {
  189. // 创建新的节点
  190. Node* newNode = createNode(target, weight);
  191. // 将新节点插入到源节点的邻接表中,顶点以下标为标准直接以头插法插入
  192. newNode->next = graph->adjacencyList[source];
  193. graph->adjacencyList[source] = newNode;
  194. }
  195. // 求顶点的出度
  196. int outDegree(Graph* graph, int vertex) {
  197. Node* currentNode = graph->adjacencyList[vertex];
  198. int outDegree = 0;
  199. while (currentNode != NULL) {
  200. outDegree++;
  201. currentNode = currentNode->next;
  202. }
  203. return outDegree;
  204. }
  205. // 求顶点的入度,遍历整个邻接表
  206. int inDegree(Graph* graph, int vertex) {
  207. int inDegree = 0;
  208. for (int i = 0; i < graph->numNodes; i++) {
  209. Node* currentNode = graph->adjacencyList[i];
  210. while (currentNode != NULL) {
  211. if (currentNode->value == vertex) {
  212. inDegree++;
  213. }
  214. currentNode = currentNode->next;
  215. }
  216. }
  217. return inDegree;
  218. }
  219. // 深度优先,递归遍历
  220. void DFS(Graph* graph, int vertex, int* visited) {
  221. visited[vertex] = 1;
  222. printf("%d ", vertex);
  223. Node* currentNode = graph->adjacencyList[vertex];
  224. while (currentNode != NULL) {
  225. int neighbor = currentNode->value;
  226. if (!visited[neighbor]) {
  227. DFS(graph, neighbor, visited);
  228. }//如果此顶点未被访问,则继续深度优先遍历
  229. currentNode = currentNode->next;
  230. }
  231. }
  232. // 广度优先遍历
  233. void BFS(Graph* graph, int startVertex) {
  234. int* visited = (int*)malloc(graph->numNodes * sizeof(int));
  235. for (int i = 0; i < graph->numNodes; i++) {
  236. visited[i] = 0;
  237. }
  238. // 创建队列
  239. int* queue = (int*)malloc(graph->numNodes * sizeof(int));
  240. int front = 0;
  241. int rear = 0;
  242. visited[startVertex] = 1;
  243. printf("%d ", startVertex);
  244. queue[rear++] = startVertex;
  245. while (front < rear) {
  246. int vertex = queue[front++];
  247. Node* currentNode = graph->adjacencyList[vertex];
  248. while (currentNode != NULL) {
  249. int neighbor = currentNode->value;
  250. if (!visited[neighbor]) {
  251. visited[neighbor] = 1;
  252. printf("%d ", neighbor);
  253. queue[rear++] = neighbor;
  254. }
  255. currentNode = currentNode->next;
  256. }
  257. }
  258. free(visited);
  259. free(queue);
  260. }
  261. // 查找顶点
  262. bool searchVertex(Graph* graph, int vertex) {
  263. for (int i = 0; i < graph->numNodes; i++) {
  264. Node* currentNode = graph->adjacencyList[i];
  265. while (currentNode != NULL) {
  266. if (currentNode->value == vertex) {
  267. return true;
  268. }
  269. currentNode = currentNode->next;
  270. }
  271. }
  272. return false;
  273. }
  274. // 判断是否为连通图
  275. bool isConnected(Graph* graph) {
  276. int* visited = (int*)malloc(graph->numNodes * sizeof(int));
  277. for (int i = 0; i < graph->numNodes; i++) {
  278. visited[i] = 0;
  279. }
  280. DFS(graph, 0, visited);
  281. for (int i = 0; i < graph->numNodes; i++) {
  282. if (visited[i] == 0) {
  283. free(visited);
  284. return false;
  285. }
  286. }
  287. free(visited);
  288. return true;
  289. }
  290. // 创建邻接矩阵
  291. int** createAdjacencyMatrix(Graph* graph) {
  292. int** matrix = (int**)malloc(graph->numNodes * sizeof(int*));
  293. for (int i = 0; i < graph->numNodes; i++) {
  294. matrix[i] = (int*)malloc(graph->numNodes * sizeof(int));
  295. for (int j = 0; j < graph->numNodes; j++) {
  296. matrix[i][j] = 0;
  297. }
  298. }
  299. for (int i = 0; i < graph->numNodes; i++) {
  300. Node* currentNode = graph->adjacencyList[i];
  301. while (currentNode != NULL) {
  302. matrix[i][currentNode->value] = currentNode->weight;
  303. currentNode = currentNode->next;
  304. }
  305. }
  306. return matrix;
  307. }
  308. int main() {
  309. int numNodes = 6;
  310. Graph* graph = createGraph(numNodes);
  311. addEdge(graph, 0, 1, 2);
  312. addEdge(graph, 0, 2, 3);
  313. addEdge(graph, 1, 2, 1);
  314. addEdge(graph, 2, 3, 4);
  315. addEdge(graph, 3, 1, 5);
  316. addEdge(graph, 3, 4, 2);
  317. addEdge(graph, 4, 0, 1);
  318. addEdge(graph, 4, 2, 3);
  319. addEdge(graph, 5, 3, 2);
  320. // 求每个顶点的出度和入度
  321. for (int i = 0; i < numNodes; i++) {
  322. printf("顶点%d的出度:%d\n", i, outDegree(graph, i));
  323. printf("顶点%d的入度:%d\n", i, inDegree(graph, i));
  324. }
  325. printf("从顶点0开始的DFS顶点序列:");
  326. int* visitedDFS = (int*)malloc(numNodes * sizeof(int));
  327. for (int i = 0; i < numNodes; i++) {
  328. visitedDFS[i] = 0;//生成所有顶点
  329. }
  330. DFS(graph, 0, visitedDFS);
  331. printf("\n");
  332. printf("从顶点0开始的BFS顶点序列:");
  333. BFS(graph, 0);
  334. printf("\n");
  335. int searchVertexValue = 2;
  336. printf("查找顶点%d:", searchVertexValue);
  337. if (searchVertex(graph, searchVertexValue)) {
  338. printf("存在\n");
  339. }
  340. else {
  341. printf("不存在\n");
  342. }
  343. printf("图是否为连通图:");
  344. if (isConnected(graph)) {
  345. printf("是\n");
  346. }
  347. else {
  348. printf("不是\n");
  349. }
  350. int** adjacencyMatrix = createAdjacencyMatrix(graph);
  351. printf("邻接矩阵:\n");
  352. for (int i = 0; i < numNodes; i++) {
  353. for (int j = 0; j < numNodes; j++) {
  354. printf("%d ", adjacencyMatrix[i][j]);
  355. }
  356. printf("\n");
  357. }
  358. }

3.4调试分析与结果测试

  3.4.1调试分析:

【问题一】
输入格式错误问题:用户输入的顶点和边的数量可能不符合要求。

解决方法是在接收输入时进行验证,确保顶点和边的数量在有效范围内。

问题二】
DFS遍历问题:DFS遍历可能陷入无限循环,或者无法访问到所有的顶点。

解决方法是使用一个标记数组来记录已经访问过的顶点,避免重复访问,并确保能够访问到所有的顶点。
   【问题三】
  BFS遍历问题:BFS遍历可能无法处理有向图中的环路,导致陷入无限循环。

解决方法是使用一个队列来保存待访问的顶点,并使用一个标记数组来记录已经访问过的顶点。
   【问题四】
  图中不存在指定顶点问题:在进行删除操作或查找操作时,如果图中不存在指定的顶点,可能会引发错误。解决方法是在操作之前进行判断,如果顶点不存在,则输出相应的提示信息。
    【问题五】
 连通图判断问题:判断图是否为连通图可能需要进行图的遍历。

解决方法是通过DFS或BFS遍历图,并检查是否能够访问到所有的顶点。

  3.4.2测试结果:

4.八皇后问题

4.1问题描述

         八皇后问题是一个古老而著名的问题,它是回溯算法的典型例题。该问题是 19 世纪德国著名数学家高斯于 1850 年提出的:在 8 行 8 列的国际象棋棋盘上摆放着 8 个皇后。若两个皇后位于同一行、同一列或同一对角线上,则称为它们为互相攻击。在国际象棋中皇后是最强大的棋子,因为它的攻击范围最大,

4.2需求分析

          编程解决八皇后问题。在 8×8 的棋盘上,放置 8 个皇后。要求使这8 个皇后不能相互攻击,即每一横行、每一列,每一对角线上均只能放置一个皇后,求出所有可能的方案,输出这些方案,并统计方案总数。

4.3算法设计与实现

         4.3.1.设计思路

      因为八个皇后每一行只能有一个占据东宫的位置,所以我们只需要定义一个一维数组,每一个数字来表示皇后所在的列数即可。我们在每摆放一个新的皇后时都要与前面的皇后进行if语句的判断,确保她们不会再同一行上,不会在直角线上(成45°或135°)(定义的一维数组已经保证每一行只会有一个皇后,如果if不成立,则返回上一个皇后的位置重新选择)。

 4.3.2主要函数说明及源程序
  1. #include<stdio.h>
  2. int main()
  3. int count = 0;//计数器,每成功摆放一次记一次
  4. for (int q1 = 0; q1 < 8; q1++)
  5. {
  6. for (int q2 = 0; q2 < 8; q2++)
  7. {
  8. if (q1 == q2 || q1 == q2 + 1 || q1 == q2 - 1)
  9. {
  10. continue;
  11. }
  12. for (int q3 = 0;q3 < 8; q3++)
  13. {
  14. if (q1 == q3 || q1 == q3 + 2 || q1 == q3-2
  15. || q2 == q3 || q2 == q3 + 1|| q2 == q3 - 1)
  16. {
  17. continue;
  18. }
  19. for (int q4 = 0; q4 < 8; q4++)
  20. {
  21. if (q1 == q4 || q1 == q4 + 3 || q1 == q4 - 3
  22. || q2 == q4 || q2 == q4 + 2|| q2 == q4- 2
  23. || q3 == q4 || q3 == q4 + 1 || q3== q4- 1)
  24. {
  25. continue;
  26. }
  27. for (int q5 = 0; q5 < 8; q5++)
  28. {
  29. if (q1 == q5 || q1 == q5 + 4 || q1 == q5 - 4
  30. || q2 == q5 || q2 == q5 + 3|| q2 == q5 - 3
  31. || q3 == q5 || q3 == q5 + 2 || q3 == q5- 2
  32. || q4 == q5 || q4 == q5 + 1 || q4 == q5 - 1)
  33. {
  34. continue;
  35. }
  36. for (int q6 = 0; q6 < 8; q6++)
  37. {
  38. if (q1 == q6 || q1 == q6 + 5 || q1 == q6 - 5
  39. || q2 == q6 || q2 == q6 + 4 || q2 == q6 - 4
  40. || q3 == q6 || q3 == q6 + 3 || q3 == q6 - 3
  41. || q4 == q6 || q4 == q6 + 2 || q4 == q6 - 2
  42. || q5 == q6 || q5 == q6 + 1 || q5 == q6 - 1)
  43. {
  44. continue;
  45. }
  46. for (int q7 = 0; q7 < 8; q7++)
  47. {
  48. if (q1 == q7 || q1 == q7 + 6 || q1 == q7 - 6
  49. || q2 == q7 || q2 == q7 + 5 || q2 == q7 - 5
  50. || q3 == q7 || q3 == q7 + 4 || q3 == q7 - 4
  51. || q4 == q7 || q4 == q7 + 3 || q4 == q7 - 3
  52. || q5 == q7 || q5 == q7 + 2 || q5 == q7 - 2
  53. || q6 == q7 || q6 == q7 + 1 || q6 == q7 - 1)
  54. {
  55. continue;
  56. }
  57. for (int q8 = 0; q8 < 8; q8++)
  58. {
  59. if (q1 == q8 || q1 == q8 + 7 || q1 == q8 - 7
  60. || q2 == q8 || q2 == q8 + 6 || q2 == q8 -6
  61. || q3 == q8 || q3 == q8 + 5 || q3 == q8 -5
  62. || q4 == q8 || q4 == q8 + 4 || q4 == q8 -4
  63. || q5 == q8 || q5 == q8 + 3 || q5 == q8 -3
  64. || q6 == q8 || q6 == q8 + 2 || q6 == q8 -2
  65. || q7 == q8 || q7 == q8 + 1 || q7 == q8 -1)
  66. {
  67. continue;
  68. }
  69. count++;
  70. printf("%d,%d,%d,%d,%d,%d,%d,%d\n", q1, q2, q3, q4,q5, q6, q7, q8);
  71. }
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. }
  79. printf("一共有%d种方法", count);
  80. return 0;
  81. }

4.4 调试分析与结果测试

   4.4.1调试分析

       【问题一】

        运行环境存在问题,在Dev C++中运行出现问题,结果出现遗漏

         解决方法:换一个编译环境,换为Visual 6.0运行成功

    4.4.2测试结果:

     

5.木棒加工问题

5.1问题描述

现有 n 根木棒,已知它们的长度和重量,要用一部木工机一根一根地加工这些木棒。该的准备时间如下:

  1. 第一根木棒需要 1 分钟的准备时间。

(2)在加工完一根长为 lenth,重为 weight 的木棒之后,接着加工一根长为lenth'(lenth<=lenth'),重为 weight'(weight<= weight')的木棒是不需要任何准备时间的。否则需要一分钟的准备时间。

5.2需求分析

给定 n(1<n≤5000)根木棒,已知它们的长度和重量,请编写程序:找到加工完所有的木棒所需的最少准备时间,以及加工这些木棒的顺序。

5.3算法设计与分析

5.3.1设计思路

      先对n根木棒按照长度进行全局排序,得到了一个长度有序而重量无序的序列(贪心先按长度排序)。\n再在每一个同一长度序列中,对重量进行局部排序。至此,长度和重量都是有序的。\n最长单调递增子序列的个数(采用动态规划),即为最终的答案。

5.3.2主要函数说明及源程序

void sort_length(int n)  //排序算法

void sort_weight(int n)   //同一长度内进行排序

 【源程序】

  1. #include <iostream>
  2. #include <malloc.h>
  3. #define max 5001
  4. typedef struct{
  5. int length, weight;
  6. }boat;
  7. boat b[max];
  8. int count = 0;
  9. using namespace std;
  10. void sort_length(int n){
  11. //排序算法
  12. int i, j;
  13. boat x;
  14. for(i=1; i<=n; i++){
  15. for(j=1; j<=n-i; j++){
  16. if(b[j].length >= b[j+1].length){
  17. x = b[j];
  18. b[j] = b[j+1];
  19. b[j+1] = x;
  20. }
  21. }
  22. }
  23. }
  24. void sort_weight(int n){
  25. boat x;
  26. int i=1, j=1, p=0;
  27. int k, s;
  28. //同一长度内进行排序
  29. for(i=1; i<=n; i++){
  30. x = b[i];
  31. j = i+1;
  32. while(b[i].length == b[j].length){
  33. j++;
  34. }
  35. p = 0;
  36. for(k=i; k<j; k++){
  37. //冒泡排序
  38. for(s=i; s<j-p-1; s++){
  39. if(b[s].weight >= b[s+1].weight){
  40. x = b[s];
  41. b[s] = b[s+1];
  42. b[s+1] = x;
  43. }
  44. }
  45. p++;
  46. }
  47. i = j-1;
  48. }
  49. for(i=1; i<=n; i++){
  50. printf("%d %d\n", b[i].length, b[i].weight);
  51. }
  52. //排序完成
  53. for(i=1; i<=n; i++){
  54. k=i;
  55. for(j=i+1; j<=n; j++){
  56. if(b[i].length == b[j].length){
  57. i = j;continue;
  58. }
  59. if(b[i].weight <= b[j].weight){
  60. i = i+1;
  61. x = b[j];
  62. //元素后移
  63. for(s=j; s>i; s--){
  64. b[s] = b[s-1];
  65. // printf("%d %d\n", b[s].length, b[s].weight);
  66. }
  67. b[i] = x;
  68. }
  69. }
  70. count++;
  71. printf("\n每一次加工的木棒\n");
  72. for(; k<=i; k++){
  73. printf("%d %d\n", b[k].length, b[k].weight);
  74. }
  75. }
  76. printf("\n总共所需要的时间:%dmin\n", count);
  77. }
  78. int main(){
  79. int n;
  80. int i;
  81. printf("请输入木棒总数:");
  82. scanf("%d", &n);
  83. printf("请输入木棒的长度和重量:");
  84. for(i=1;i<=n;i++){
  85. scanf("%d%d", &b[i].length, &b[i].weight);
  86. }
  87. printf("先按照长度进行排序。\n");
  88. sort_length(n);
  89. for(i=1; i<=n; i++){
  90. printf("%d %d\n", b[i].length, b[i].weight);
  91. }
  92. printf("\n再在排好序的基础上按照重量排序。\n");
  93. sort_weight(n);
  94. return 0;
  95. }

5.4调试分析与结果测试

  5.4.1调试分析

    【问题一】

         1.输入数据的格式错误:如果输入的木棒数量小于等于1或者大于5000,或者木棒的长度和重量不符合要求,程序可能无法正确处理这些数据。

解决方法:注意程序所给的提示

     5.4.2测试结果:

三.课程设计总结

     此次课程设计的题目可以说经典但是有点难度,主要体现在对于题目的理解和运用程序难以实现,在程序运行过程中还出现了包括编译环境在内的一系列问题,。我参照了网上的很多代码,几乎都需要自己的理解加上改写,这对于我是非常大的难题。好在班上有和我选一样的题的同学,这使我们可以一起探讨关于编程以及算法设计上的问题。也帮我解决了课程设计中的绝大多数问题。与此同时,经过这次的课程设计,我的对于程序的编写和改写能力得到了明显的提高,对结果的分析能力,资料搜集、阅读及整理能力,以及良好的沟通、表达能力都显著提升。也加深对常用数据结构理论知识的理解,能够运用各种数据结构与算法,独立分析、设计、解决问题。通过良好的文字、口头等沟通方式,表达个人对系统设计、实施及测试结论等方面的见解。

四.参考文献

  1. 谭浩强.c程序设计(第二版)北京:清华大学出版社,2004
  2. 严蔚敏,吴伟民.数据结构.北京:清华大学出版社,2005
  3. 林劼,刘震,陈端兵等.数据结构与算法[M].北京大学出版社,2019.

陈锐,张志锋,马军霞.数据结构与算法详解[M]

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号