图应用之最小生成树(头歌教学实践平台)

第1关:最小生成树算法

任务描述

本关任务:编写代码完成 Prim 算法的 Python 实现,求出图的最小生成树。

相关知识

为了完成本关任务,你需要掌握: 1.最小生成树的基本概念; 2.如何实现 Prim 算法。

最小生成树

为了说明图的最小生成树算法,首先我们来考虑一个在互联网中网游设计者和网络收音机所面临的问题:信息广播问题。网游需要让所有玩家获知其他玩家所在的位置,收音机则需要让所有听众获取直播的音频数据。图 1 展示了这个广播问题,最上方是一个广播的服务器,其他位置有 4 台接收的收听设备,通过路由器网络可以将广播数据发送出去,从而实现将相同的数据发送到不同的结点。

图1 信息广播问题

为了解决信息广播问题,有以下几种方法:

  1. 单播解法

信息广播问题最简单的解法是由广播源维护一个收听者的列表,将每条消息向每个收听者发送一次。由于图 1 中有 4 个收听者,每条消息将会被发送 4 次。在路由器网络中,每个消息都采用最短路径算法到达收听者。

但是这种方法会导致某些路由器重复发送相同消息,比如路由器 A 会处理 4 次相同消息,而 B、D 位于其它 3 个收听者的最短路径上,则各会处理转发 3 次相同消息。这样就会给该路由器网络增加负担,从而产生许多额外流量。

  1. 洪水解法

是一种信息广播问题的暴力解法,该方法将每条消息在路由器间散布出去,所有路由器都将收到的消息转发到自己相邻的路由器和收听者。显然,如果没有任何限制,这个方法将造成网络洪水灾难,很多路由器和收听者会不断重复收到相同的消息,永不停止。

所以洪水解法一般会给每条消息附加一个生命值(TTL:Time To Live),初始设置为从消息源到最远收听者的距离。每当一个路由器收到一条消息,如果其 TTL 值大于 0,则将 TTL 减少 1 后再转发出去;如果 TTL 等于 0 了,则直接抛弃这个消息。TTL 的设置防止了灾难发生,但这种洪水解法显然比前述的单播方法所产生的流量还要大。

  1. 最小生成树方法

是信息广播问题的最优解法,该方法依赖于在路由器关系图上选取具有最小权重的生成树。其中生成树表示为拥有图中所有的顶点和最少数量的边,以保持连通的子图。也就是说,从生成树中移去一条边,这个树就无法连通。

对于图 G(V,E),其最小生成树 T 定义为包含所有顶点 V,以及边 E 的无圈子集,并且边上权重之和最小。

图 2 展示了为了解决图 1 中的信息广播问题而形成的最小生成树。每一个路由器向作为生成树一部分的任意相邻路由器发送信息,这样信息广播就只需要从 A 开始,沿着树的路径层次向下传播。在此问题中,A 向 B 发送信息,B 向 D 和 C 发送信息,D 向 E 发送信息,E 向 F 发送信息,F 向 G 发送信息。这样每个路由器只需要处理 1 次消息就能让所有收听者都能够接收到,同时总费用最小。

图2 广播问题的最小生成树

Prim 算法

以上介绍了最小生成树在信息广播中的应用,最小生成树问题可以使用 Prim 算法来解决。Prim 算法属于“贪心算法”,即每步都沿着最小权重的边向前搜索。Prim 算法构造最小生成树的思路很简单,如果 T 还不是生成树,则反复做:

  1. 找到一条最小权重的可以安全添加的边;

  2. 将边添加到树 T。

其中“可以安全添加的边”定义为一端顶点在树中另一端不在树中的边,以便保持树的无圈特性。

Dijkstra 算法的实现类似,我们在顶点 Vertex 类中添加了 dist 和 pred 实例变量,dist 用来表示该顶点到已并入当前生成树的顶点的最短距离边上的权值,pred 用来表示该最短距离边另一端在树中的顶点。Vertex 类中对这两个实例变量的定义和相关方法的代码示例如下:

  1. class Vertex:
  2. def __init__(self,num):
  3. ……
  4. self.dist = sys.maxsize # 距离 dist
  5. self.pred = None # 前驱
  6. def setDistance(self,d): # 设置 dist
  7. self.dist = d
  8. def setPred(self,p): # 设置前驱
  9. self.pred = p
  10. def getDistance(self): # 获取 dist
  11. return self.dist
  12. def getPred(self): # 获取前驱
  13. return self.pred
  14. ……

同时还需要使用一个优先队列来控制顶点的优先级,其中决定顺序的参量是顶点的 dist 值。我们采用二叉堆的数据结构来实现优先队列,相关知识请参考二叉堆实现的优先队列。与此不同的是,为了对优先队列进行重排序,在 PriorityQueue 类中还添加了decreaseKey方法,当队列中某个顶点的 dist 减小的时候,将会对这个顶点进行调整,在堆中上浮到最终正确的位置。下面为一些相关的基本操作定义:

  • PriorityQueue():创建一个新的空优先队列(二叉堆)对象
  • buildHeap(list):从一个 key 列表创建新堆
  • insert(k):加入一个新数据项到堆中
  • findMin():返回堆中的最小项,最小项仍保留在堆中
  • delMin():返回堆中的最小项,同时从堆中删除
  • isEmpty():返回堆是否为空
  • decreaseKey(val,amt):顶点 val 的 key 改变为 amt,并对堆进行重新调整

以下为 Prim 算法求解最小生成树的一个简单示例。

对于图 3 所示的图,我们将顶点 A 作为开始顶点。最初,只将开始顶点 A 的 dist 设置为 0,而其他所有顶点的 dist 都设置为最大整数 sys.maxsize,并且全部加入到优先队列中,在图中顶点的 dist 用 d 表示。首先,从优先队列中将顶点 A 出队,将顶点 A 作为当前生成树。从 A 到顶点 B、C 的距离 2 和 3 都小于这两个顶点的 dist 初始值 sys.maxsize,于是更新顶点 B、C 的 dist 分别为 2 和 3。这时 B 和 C 已到了优先队列的前端,Prim 算法结果和优先队列 PQ 的状态如图 3 所示。

图3 顶点 A 出队,更新各顶点 dist

接下来需要寻找一条最小权重的可以安全添加的边,即找到一个与当前生成树中顶点距离最近的顶点。由于顶点 B 的 dist 最小,位于优先队列的最前端,于是将 B 出队,选择从 A 到 B 的这条边,将 B 加入到当前生成树。接下来直接对顶点 B 到未访问相邻顶点 C、D、E 的距离与顶点的 dist 进行比较,若距离更小,则将顶点的 dist 更新为较小值。将 D 的 dist 更新为从 B 到 D 的距离 1,C 的 dist 更新为从 B 到 C 的距离 1,E 的 dist 更新为从 B 到 E 的距离 4。根据顶点新的 dist 值对优先队列重新排序,这一步的算法结果和优先队列 PQ 的状态如图 4 所示。

图4 选择顶点 A、B 间的边

此时位于优先队列前端的是顶点 C,于是将 C 出队,选择从 B 到 C 的这条边,将 C 加入到当前生成树。接下来对顶点 C 到未访问相邻顶点 F 的距离与 F 的 dist 进行比较,距离 5 小于 F 的初始 dist,直接将 F 的 dist 更新为从 C 到 F 的距离 5。根据顶点新的 dist 值对优先队列重新排序,这一步的算法结果和优先队列 PQ 的状态如图 5 所示。

 图5 选择顶点 B、C 间的边

此时位于优先队列前端的是顶点 D,于是将 D 出队,选择从 B 到 D 的这条边,将 D 加入到当前生成树。由于从 D 到 E 的距离 1 小于 E 的 dist 值 4,则将 E 的 dist 更新为 1。根据顶点新的 dist 值对优先队列重新排序,这一步的算法结果和优先队列 PQ 的状态如图 6 所示。

图6 选择顶点 B、D 间的边

此时位于优先队列前端的是顶点 E,于是将 E 出队,选择从 D 到 E 的这条边,将 E 加入到当前生成树。由于从 E 到 F 的距离 1 小于 F 的 dist 值 5,则将 F 的 dist 更新为 1。根据顶点新的 dist 值对优先队列重新排序,这一步的算法结果和优先队列 PQ 的状态如图 7 所示。

图7 选择顶点 B、E 间的边

此时位于优先队列前端的是顶点 F,于是将 F 出队,选择从 E 到 F 的这条边,将 F 加入到当前生成树。由于从 F 到 G 的距离 1 小于 G 的 dist 值,则将 G 的 dist 更新为 1。根据顶点新的 dist 值对优先队列重新排序,这一步的算法结果和优先队列 PQ 的状态如图 8 所示。

图8 选择顶点 E、F 间的边

此时位于优先队列的只有顶点 G,于是将 G 出队,选择从 F 到 G 的这条边,将 G 加入到当前生成树。由于队列已空,Prim 算法结束,求出的最小生成树如图 9 所示,其中所有边的权值总和最小,同时也可以发现所有顶点的 dist 值总和即为所求最小生成树边上权值总和。

图9 选择顶点 F、G 间的边

编程要求

在右侧编辑器中的 Begin-End 区间补充代码,根据 Prim 算法的算法思想和所展示出的优先队列 PriorityQueue 类,完成prim方法,求出无向赋权图的最小生成树以及边上的权值总和。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确的数值,只有所有数据全部计算正确才能通过测试:

测试输入:

  1. 7,0 1 2,0 2 3,1 2 1,1 3 1,3 4 1,1 4 4,2 5 5,4 5 1,5 6 1

输入说明:输入字符串第一个逗号前的数值表示所创建的无向图的顶点数,剩下的部分同样以逗号进行分隔。分隔成的每一小段又以空格分隔成三部分,前两部分表示所添加边两端的顶点,最后一部分表示边上的权值。

预期输出:

  1. 7

输出说明:输出为对所创建图以 0 为开始顶点,通过 Prim 算法求出的最小生成树边上的权值总和。

测试输入:

  1. 6,0 1 5,0 5 2,1 2 4,2 3 9,3 4 7,3 5 3,5 4 8,5 2 1

预期输出:

  1. 17

提示:

  1. from pythonds.graphs import PriorityQueue,Graph
  2. g = Graph()
  3. g.addVertex(0)
  4. g.addVertex(1)
  5. g.addEdge(0, 1, 5)
  6. pq = PriorityQueue()
  7. pq.buildHeap([(v.getDistance(), v) for v in g])
  8. g.addVertex(2)
  9. g.addEdge(0, 2, 6)
  10. for v2 in g:
  11. if v2 not in pq:
  12. cost = g.vertices[0].getWeight(v2)
  13. print(cost)

提示说明:根据该提示可知道如何判定某顶点是否在优先队列中、如何获取两顶点间边上的权值,Graph 和 Vertex 类的相关知识请参考图抽象数据类型的 Pyth的 Python 实现

输出:

  1. 6
import sys

'''请在Begin-End之间补充代码, 完成Prim函数'''
class PriorityQueue:
    def __init__(self):
        self.heapArray = [(0,0)]  # 初始化一个列表,用来保存堆数据
        self.currentSize = 0    # 用来跟踪记录堆当前的大小

    # 从无序表建立一个堆
    def buildHeap(self,alist):
        self.currentSize = len(alist)
        self.heapArray = [(0,0)]
        for i in alist:
            self.heapArray.append(i)
        i = len(alist) // 2            
        while (i > 0):
            self.percDown(i)
            i = i - 1
                        
    def percDown(self,i):
        while (i * 2) <= self.currentSize:
            mc = self.minChild(i)
            if self.heapArray[i][0] > self.heapArray[mc][0]:
                tmp = self.heapArray[i]
                self.heapArray[i] = self.heapArray[mc]
                self.heapArray[mc] = tmp
            i = mc

    # 求出最小子结点
    def minChild(self,i):
        if i*2 > self.currentSize:
            return -1
        else:
            if i*2 + 1 > self.currentSize:
                return i*2
            else:
                if self.heapArray[i*2][0] < self.heapArray[i*2+1][0]:
                    return i*2
                else:
                    return i*2+1

    # 不断交换,直到新结点“上浮”到正确位的置来保持堆次序
    def percUp(self,i):
        while i // 2 > 0:
            if self.heapArray[i][0] < self.heapArray[i//2][0]:
               tmp = self.heapArray[i//2]
               self.heapArray[i//2] = self.heapArray[i]
               self.heapArray[i] = tmp
            i = i//2

    # 添加新的的数据
    def add(self,k):
        self.heapArray.append(k)
        self.currentSize = self.currentSize + 1
        self.percUp(self.currentSize)

    # 移走堆中的最小项
    def delMin(self):
        retval = self.heapArray[1][1]
        self.heapArray[1] = self.heapArray[self.currentSize]
        self.currentSize = self.currentSize - 1
        self.heapArray.pop()
        self.percDown(1)
        return retval

    # 返回堆是否为空
    def isEmpty(self):
        if self.currentSize == 0:
            return True
        else:
            return False

    # 结点 val 的 key 改变为 amt,并对堆进行重新调整
    def decreaseKey(self,val,amt):
        done = False
        i = 1
        myKey = 0
        while not done and i <= self.currentSize:  # 找到顶点val
            if self.heapArray[i][1] == val:
                done = True
                myKey = i
            else:
                i = i + 1
        if myKey > 0:
            self.heapArray[myKey] = (amt,self.heapArray[myKey][1])
            self.percUp(myKey)
            
    def __contains__(self,vtx):
        for pair in self.heapArray:
            if pair[1] == vtx:
                return True
        return False
        
def prim(G,start):
    pq = PriorityQueue()
    for v in G:
        v.setDistance(sys.maxsize)  # 所有顶点的dist都设置为最大值
        v.setPred(None)   # 设置所有的顶点的前驱
    start.setDistance(0)   # 设置开始顶点的dist为0
    pq.buildHeap([(v.getDistance(), v) for v in G])  # 对所有顶点建堆,形成优先队列
    while not pq.isEmpty():  # 当优先队列不为空时做以下操作
        # 从优先队列中出队一个顶点作为currentVert
        # ********** Begin ********** #    
        currentVert = pq.delMin()
        # ********** End ********** #
        for nextVert in currentVert.getConnections():  # 对与当前顶点相邻的所有顶点进行扫描
            # 给newCost赋值为当前顶点与相邻顶点nextVert之间边上的权重
            # 若该顶点在优先队列中(不在生成树中)并且与当前生成树的距离小于之前的dist,就进行更新
            # 修改该顶点的前驱
            # 修改该顶点的dist
            # ********** Begin ********** #    
            newCost = currentVert.getWeight(nextVert)
            if nextVert in pq and newCost < nextVert.getDistance():
                nextVert.setPred(currentVert)
                nextVert.setDistance(newCost)
            # ********** End ********** #
                pq.decreaseKey(nextVert,newCost)  # 优先队列重排

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
谭浩强教授,我国著名计算机教育专家。1934年生。1958年清华大学毕业。学生时代曾担任清华大学学生会主席、北京市人民代表。他是我国计算机普及和高校计算机基础教育开拓者之一,现任全国高等院校计算机基础教育研究会会长、教育部全国计算机应用技术证书考试委员会主任委员。 谭浩强教授创造了3个世界纪录:(1)20年来他(及和他人合作)共编著出版了130本计算机著作,此外主编了250多本计算机书籍,是出版科技著作数量最多的人。(2)他编著和主编的书发行量超过4500万册,是读者最多的科技作家。我国平均每30人、知识分子每1.5人就拥有1本谭浩强教授编著的书。(3)他和别人合作编著的《BASIC语言》发行了1200万册,创科技书籍发行量的世界纪录。此外,他编著的《C程序设计》发行了600万册。他曾在中央电视台主讲了BASIC,FORTRAN,COBOL,Pascal,QBASIC,C,Visual Basic七种计算机语言,观众超过300万人。 在我国学习计算机的人中很少有不知道谭浩强教授的。他善于用容易理解的方法和语言说明复杂的概念。许多人认为他开创了计算机书籍贴近大众的新风,为我国的计算机普及事业做出了重要的贡献。 谭浩强教授曾获全国高校教学成果国家级奖、国家科技进步奖,以及北京市政府授予的“有突出贡献专家”称号。《计算机世界》报组织的“世纪评选”把他评为我国“20世纪最有影响的IT人物”10个人之一(排在第2位)。他的功绩是把千百万群众带入计算机的大门。 1 C语言概述 1.1 C语言的发展过程 1.2 当代最优秀的程序设计语言 1.3 C语言版本 1.4 C语言的特点 1.5 面向对象的程序设计语言 1.6 C和C++ 1.7 简单的C程序介绍 1.8 输入和输出函数 1.9 C源程序的结构特点 1.10 书写程序时应遵循的规则 1.11 C语言的字符集 1.12 C语言词汇 1.13 Turbo C 2.0 集成开发环境的使用 1.13.1 Turbo C 2.0 简介和启动 1.13.2 Turbo C 2.0 集成开发环境 1.13.3 File菜单 1.13.4 Edit 菜单 1.13.5 Run 菜单 1.13.6 Compile 菜单 11.13.7 Project 菜单 1.13.8 Options菜单 1.13.9 Debug 菜单 1.13.10 Break/watch 菜单 1.13.11 Turbo C 2.0 的配置文件 2 程序的灵魂—算法 2.1 算法的概念 21 2.2 简单算法举例 21 2.3 算法的特性 24 2.4 怎样表示一个算法 24 2.4.1 用自然语言表示算法 24 2.4.2 用流程表示算法 24 2.4.3 三种基本结构和改进的流程 28 2.4.4 用N-S 流程表示算法 29 2.4.5 用伪代码表示算法 30 2.4.6 用计算机语言表示算法 31 2.5 结构化程序设计方法 31 3 数据类型、运算符与表达式 3.1 C语言的数据类型 32 3.2 常量与变量 33 23.2.1 常量和符号常量 33 3.2.2 变量 33 3.3 整型数据 34 3.3.1 整型常量的表示方法 34 3.3.2 整型变量 35 3.4 实型数据 37 3.4.1 实型常量的表示方法 37 3.4.2 实型变量 38 3.4.3 实型常数的类型 39 3.5 字符型数据 39 3.5.1 字符常量 39 3.5.2 转义字符 39 3.5.3 字符变量 40 3.5.4 字符数据在内存中的存储形式及使用方法 41 3.5.5 字符串常量 41 3.5.6 符号常量 42 3.6 变量赋初值 42 3.7 各类数值型数据之间的混合运算 43 3.8 算术运算符和算术表达式 44 3.8.1 C运算符简介 44 3.8.2 算术运算符和算术表达式 45 3.9 赋值运算符和赋值表达式 47 33.10 逗号运算符和逗号表达式 48 3.11 小结 49 3.11.1 C的数据类型 49 3.11.2 基本类型的分类及特点 49 3.11.3 常量后缀 49 3.11.4 常量类型 49 3.11.5 数据类型转换 49 3.11.6 运算符优先级和结合性 50 表达式 50 4 最简单的 C程序设计—顺序程序设计 4.1 C语句概述 51 4.2 赋值语句 53 4.3 数据输入输出的概念及在 C 语言中的实现 54 4.4 字符数据的输入输出 54 4.4.1 putchar 函数(字符输出函数) 54 4.4.2 getchar函数(键盘输入函数) 55 4.5 格式输入与输出 55 4.5.1 printf 函数(格式输出函数) 56 4.5.2 scanf函数(格式输入函数) 58 顺序结构程序设计举例 60 45 分支结构程序 5.1 关系运算符和表达式 61 5.1.1 关系运算符及其优先次序 61 5.1.2 关系表达式 61 5.2 逻辑运算符和表达式 62 5.2.1 逻辑运算符极其优先次序 62 5.2.2 逻辑运算的值 63 5.2.3 逻辑表达式 63 5.3 if 语句 64 5.3.1 if语句的三种形式 64 5.3.2 if语句的嵌套 67 5.3.3 条件运算符和条件表达式 69 5.4 switch语句 70 5.5 程序举例 71 6 循环控制 6.1 概述 71 6.2 goto 语句以及用goto 语句构成循环 71 6.3 while语句 72 6.4 do-while语句 74 6.5 for 语句 76 6.6 循环的嵌套 79 56.7 几种循环的比较 79 6.8 break 和 continue语句 79 6.8.1 break 语句 79 6.8.2 continue 语句 80 6.9 程序举例 81 7 数组 7.1 一维数组的定义和引用 82 7.1.1 一维数组的定义方式 82 7.1.2 一维数组元素的引用 83 7.1.3 一维数组的初始化 84 7.1.4 一维数组程序举例 84 7.2 二维数组的定义和引用 86 7.2.1 二维数组的定义 86 7.2.2 二维数组元素的引用 86 7.2.3 二维数组的初始化 87 7.2.4 二维数组程序举例 89 7.3 字符数组 89 7.3.1 字符数组的定义 89 7.3.2 字符数组的初始化 89 7.3.3 字符数组的引用 90 7.3.4 字符串和字符串结束标志 91 67.3.5 字符数组的输入输出 91 7.3.6 字符串处理函数 92 7.4 程序举例 94 本章小结 97 8 函 数 8.1 概述 98 8.2 函数定义的一般形式 99 8.3 函数的参数和函数的值 100 8.3.1 形式参数和实际参数 101 8.3.2 函数的返回值 102 8.4 函数的调用 106 8.4.1 函数调用的一般形式 106 8.4.2 函数调用的方式 106 8.4.3 被调用函数的声明和函数原型 107 8.5 函数的嵌套调用 108 8.6 函数的递归调用 109 8.7 数组作为函数参数 110 8.8 局部变量和全局变量 112 8.8.1 局部变量 113 8.8.2 全局变量 119 8.9 变量的存储类别 120 78.9.1 动态存储方式与静态动态存储方式 120 8.9.2 auto变量 120 8.9.3 用static 声明局部变量 121 8.9.4 register 变量 122 用extern 声明外部变量 123 9 预处理命令 9.1 概述 124 9.2 宏定义 125 9.2.1 无参宏定义 126 9.2.2 带参宏定义 127 9.3 文件包含 128 9.4 条件编译 130 9.5 本章小结 10 指针 10.1 地址指针的基本概念 131 10.2 变量的指针和指向变量的指针变量 132 10.2.1 定义一个指针变量 133 10.2.2 指针变量的引用 133 10.2.3 指针变量作为函数参数 137 10.2.4 指针变量几个问题的进一步说明 140 810.3 数组指针和指向数组的指针变量 141 10.3.1 指向数组元素的指针 142 10.3.2 通过指针引用数组元素 143 10.3.3 数组名作函数参数 146 10.3.4 指向多维数组的指针和指针变量 148 10.4 字符串的指针指向字符串的针指变量 150 10.4.1 字符串的表示形式 152 10.4.2 使用字符串指针变量与字符数组的区别 158 10.5 函数指针变量 159 10.6 指针型函数 160 10.7 指针数组和指向指针的指针 161 10.7.1 指针数组的概念 161 10.7.2 指向指针的指针 164 10.7.3 main 函数的参数 166 10.8 有关指针的数据类型和指针运算的小结 167 10.8.1 有关指针的数据类型的小结 167 10.8.2 指针运算的小结 167 10.8.3 void 指针类型 168 11 结构体与共用体 11.1 定义一个结构的一般形式 170 11.2 结构类型变量的说明 172 911.3 结构变量成员的表示方法 174 11.4 结构变量的赋值 174 11.5 结构变量的初始化 175 11.6 结构数组的定义 175 11.7 结构指针变量的说明和使用 177 11.7.1 指向结构变量的指针 177 11.7.2 指向结构数组的指针 179 11.7.3 结构指针变量作函数参数 180 11.8 动态存储分配 181 11.9 链表的概念 182 11.10 枚举类型 184 11.10.1 枚举类型的定义和枚举变量的说明 184 11.10.2 枚举类型变量的赋值和使用 185 11.11 类型定义符typedef 12 位运算 12.1 位运算符C语言提供了六种位运算符: 189 12.1.1 按位与运算 191 12.1.2 按位或运算 192 12.1.3 按位异或运算 192 12.1.4 求反运算 193 12.1.5 左移运算 193 1012.1.6 右移运算 193 12.2 位域(位段) 194 12.3 本章小结 13 文件 13.1 C文件概述 197 13.2 文件指针 198 13.3 文件的打开与关闭 199 13.3.1 文件的打开(fopen 函数) 200 13.3.2 文件关闭函数(fclose函数) 202 13.4 文件的读写 204 13.4.1 字符读写函数fgetc 和fputc 204 13.4.2 字符串读写函数fgets 和fputs 208 13.4.3 数据块读写函数fread 和fwtrite 209 13.4.4 格式化读写函数fscanf和fprintf 201 13.5 文件的随机读写 202 13.5.1 文件定位 202 13.5.2 文件的随机读写 203 13.6 文件检测函数 204 13.6.1 文件结束检测函数 feof函数 204 13.6.2 读写文件出错检测函数 205 1113.6.3 文件出错标志和文件结束标志置 0 函数 206 13.7 C库文件 208 13.8 本章小结 第1篇 基本知识 第1章 C++的初步知识 *1.1 从C到C++ *1.2 最简单的C++程序 1.3 C++程序的构成和书写形式 1.4 C++程序的编写和实现 1.5 关于C++上机实践 习题 第2章 数据类型与表达式 2.1 C++的数据类型 2.2 常量 2.2.1 什么是常量 2.2.2 数值常量 2.2.3 字符常量 2.2.4 符号常量 2.3 变量 2.3.1 什么是变量 2.3.2 变量名规则 2.3.3 定义变量 2.3.4 为变量赋初值 2.3.5 常变量 2.4 C++的运算符 2.5 算术运算符与算术表达式 2.5.1 基本的算术运算符 2.5.2 算术表达式和运算符的优先级与结合性 2.5.3 表达式中各类数值型数据间的混合运算 2.5.4 自增和自减运算符 2.5.5 强制类型转换运算符 2.6 赋值运算符与赋值表达式 2.6.1 赋值运算符 2.6.2 赋值过程中的类型转换 2.6.3 复合的赋值运算符 2.6.4 赋值表达式 2.7 逗号运算符与逗号表达式 习题 第2篇 面向过程的程序设计 第3章 程序设计初步 3.1 面向过程的程序设计和算法 3.1.1 算法的概念 3.1.2 算法的表示 3.2 C++程序和语句 3.3 赋值语句 3.4 C++的输入与输出 *3.4.1 输入流与输出流的基本操作 *3.4.2 在输入流与输出流中使用控制符 3.4.3 用getchar和putchar函数进行字符的输入和输出 3.4.4 用scanf和printf函数进行输入和输出 3.5 编写顺序结构的程序 3.6 关系运算和逻辑运算 3.6.1 关系运算和关系表达式 3.6.2 逻辑常量和逻辑变量 3.6.3 逻辑运算和逻辑表达式 3.7 选择结构和if语句 3.7.1 if语句的3种形式 3.7.2 if语句的嵌套 3.8 条件运算符和条件表达式 3.9 多分支选择结构和switch语句 3.10 编写选择结构的程序 3.11 循环结构和循环语句 3.11.1 用while语句构成循环 3.11.2 用do-while语句构成循环 3.11.3 用for语句构成循环 3.11.4 几种循环的比较 3.12 循环的嵌套 3.13 break语句和continue语句 3.14 编写循环结构的程序 习题 第4章 函数与预处理 4.1 概述 4.2 定义函数的一般形式 4.2.1 定义无参函数的一般形式 4.2.2 定义有参函数的一般形式 4.3 函数参数和函数的值 4.3.1 形式参数和实际参数 4.3.2 函数的返回值 4.4 函数的调用 4.4.1 函数调用的一般形式 4.4.2 函数调用的方式 4.4.3 对被调用函数的声明和函数原型 *4.5 内置函数 *4.6 函数的重载 *4.7 函数模板 *4.8 有默认参数的函数 4.9 函数的嵌套调用 4.10 函数的递归调用 4.11 局部变量和全局变量 4.11.1 局部变量 4.11.2 全局变量 4.12 变量的存储类别 4.12.1 动态存储方式与静态存储方式 4.12.2 自动变量 4.12.3 用static声明静态局部变量 4.12.4 用register声明寄存器变量 4.12.5 用extern声明外部变量 4.12.6 用static声明静态外部变量 4.13 变量属性小结 4.14 关于变量的声明和定义 4.15 内部函数和外部函数 4.15.1 内部函数 4.15.2 外部函数 4.16 预处理命令 4.16.1 宏定义 4.16 2 “文件包含”处理 4.16.3 条件编译 习题 第5章 数组 5.1 数组的概念 5.2 一维数组的定义和引用 5.2.1 定义一维数组 5.2.2 引用一维数组的元素 5.2.3 一维数组的初始化 5.2.4 一维数组程序举例 5.3 二维数组的定义和引用 5.3.1 定义二维数组 5.3.2 二维数组的引用 5.3.3 二维数组的初始化 5.3.4 二维数组程序举例 5.4 用数组名作函数参数 5.5 字符数组 5.5.1 字符数组的定义和初始化 5.5.2 字符数组的赋值与引用 5.5.3 字符串和字符串结束标志 5.5.4 字符数组的输入输出 5.5.5 字符串处理函数 5.5.6 字符数组应用举例 *5.6 C++处理字符串的方法——字符串类与字符串变量 5.6.1 字符串变量的定义和引用 5.6.2 字符串变量的运算 5.6.3 字符串数组 5.6.4 字符串运算举例 习题 第6章 指针 6.1 指针的概念 6.2 变量与指针 6.2.1 定义指针变量 6.2.2 引用指针变量 6.2.3 指针作为函数参数 6.3 数组与指针 6.3.1 指向数组元素的指针 6.3.2 用指针变量作函数参数接收数组地址 6.3.3 多维数组与指针 6.4 字符串与指针 6.5 函数与指针 6.5.1 用函数指针变量调用函数 6.5.2 用指向函数的指针作函数参数 6.6 返回指针值的函数 6.7 指针数组和指向指针的指针 6.7.1 指针数组的概念 6.7.2 指向指针的指针 6.8 有关指针的数据类型和指针运算的小结 6.8.1 有关指针的数据类型的小结 6.8.2 指针运算小结 *6.9 引用 6.9.1 什么是变量的引用 6.9.2 引用的简单使用 6.9.3 引用作为函数参数 习题 第7章 自定义数据类型 7.1 结构体类型 7.1.1 结构体概述 7.1.2 结构体类型变量的定义方法及其初始化 7.1.3 结构体变量的引用 7.1.4 结构体数组 7.1.5 指向结构体变量的指针 7.1.6 结构体类型数据作为函数参数 *7.1.7 动态分配和撤销内存的运算符new和delete 7.2 共用体 7.2.1 共用体的概念 7.2.2 对共用体变量的访问方式 7.2.3 共用体类型数据的特点 7.3 校举类型 7.4 用typedef声明类型 习题 第3篇 基于对象的程序设计 第8章 类和对象 8.1 面向对象程序设计方法概述 8.1.1 什么是面向对象的程序设计 8.1.2 面向对象程序设计的特点 8.1.3 类和对象的作用 8.1.4 面向对象的软件开发 8.2 类的声明和对象的定义 8.2.1 类和对象的关系 8.2.2 声明类类型 8.2.3 定义对象的方法 8.2.4 类和结构体类型的异同 8.3 类的成员函数 8.3.1 成员函数的性质 8.3.2 在类外定义成员函数 8.3.3 inline成员函数 8.3.4 成员函数的存储方式 8.4 对象成员的引用 8.4.1 通过对象名和成员运算符访问对象中的成员 8.4.2 通过指向对象的指针访问对象中的成员 8.4.3 通过对象的引用变量来访问对象中的成员 8.5 类的封装性和信息隐蔽 8.5.1 公用接口与私有实现的分离 8.5.2 类声明和成员函数定义的分离 8.5.3 面向对象程序设计中的几个名词 8.6 类和对象的简单应用举例 习题 第9章 关于类和对象的进一步讨论 9.1 构造函数 9.1.1 对象的初始化 9.1.2 构造函数的作用 9.1.3 带参数的构造函数 9.1.4 用参数初始化表对数据成员初始化 9.1.5 构造函数的重载 9.1.6 使用默认参数的构造函数 9.2 析构函数 9.3 调用构造函数和析构函数的顺序 9.4 对象数组 9.5 对象指针 9.5.1 指向对象的指针 9.5.2 指向对象成员的指针 9.5.3 this指针 9.6 共用数据的保护 9.6.1 常对象 9.6.2 常对象成员 9.6.3 指向对象的常指针 9.6.4 指向常对象的指针变量 9.6.5 对象的常引用 9.6.6 const型数据的小结 9.7 对象的动态建立和释放 9.8 对象的赋值和复制 9.8.1 对象的赋值 9.8.2 对象的复制 9.9 静态成员 9.9.1 静态数据成员 9.9.2 静态成员函数 9.10 友元 9.10.1 友元函数 9.10.2 友元类 9.11 类模板 习题 第10章 运算符重载 10.1 什么是运算符重载 10.2 运算符重载的方法 10.3 重载运算符的规则 10.4 运算符重载函数作为类成员函数和友元函数 10.5 重载双目运算符 10.6 重载单目运算符 10.7 重载流插入运算符和流提取运算符 10.7.1 重载流插入运算符“<<” 10.7.2 重载流提取运算符“>>” 10.8 不同类型数据间的转换 10.8.1 标准类型数据间的转换 10.8.2 转换构造函数 10.8.3 类型转换函数 习题 第4篇 面向对象的程序设计 第11章 继承与派生 11.1 继承与派生的概念 11.2 派生类的声明方式 11.3 派生类的构成 11.4 派生类成员的访问属性 11.4.1 公用继承 11.4.2 私有继承 11.4.3 保护成员和保护继承 11.4.4 多级派生时的访问属性 11.5 派生类的构造函数和析构函数 11.5.1 简单的派生类的构造函数 11.5.2 有子对象的派生类的构造函数 11.5.3 多层派生时的构造函数 11.5.4 派生类构造函数的特殊形式 11.5.5 派生类的析构函数 11.6 多重继承 11.6.1 声明多重继承的方法 11.6.2 多重继承派生类的构造函数 11.6.3 多重继承引起的二义性问题 11.6.4 虚基类 11.7 基类与派生类的转换 11.8 继承与组合 11.9 继承在软件开发中的重要意义 习题 第12章 多态性与虚函数 12.1 多态性的概念 12.2 一个典型的例子 12.3 虚函数 12.3.1 虚函数的作用 12.3.2 静态关联与动态关联 12.3.3 在什么情况下应当声明虚函数 12.3.4 虚析构函数 12.4 纯虚函数与抽象类 12.4.1 纯虚函数 12.4.2 抽象类 12.4.3 应用实例 习题 第13章 输入输出流 13.1 C++的输入和输出 13.1.1 输入输出的含义 13.1.2 C++的I/O对C的发展——类型安全和可扩展性 13.1.3 C++的输入输出流 13.2 标准输出流 13.2.1 cout,cerr和clog流 13.2.2 格式输出 13.2.3 用流成员函数put输出字符 13.3 标准输入流 13.3.1 cin流 13.3.2 用于字符输入的流成员函数 13.3.3 istream类的其他成员函数 13.4 文件操作与文件流 13.4.1 文件的概念 13.4.2 文件流类与文件流对象 13.4.3 文件的打开与关闭 13.4.4 对ASCII文件的操作 13.4.5 对二进制文件的操作 13.5 字符串流 习题 第14章 C++工具 14.1 异常处理 14.1.1 异常处理的任务 14.1.2 异常处理的方法 14.1.3 在函数声明中进行异常情况指定 14.1.4 在异常处理中处理析构函数 14.2 命名空间 14.2.1 为什么需要命名空间 14.2.2 什么是命名空间 14.2.3 使用命名空间解决名字冲突 14.2.4 使用命名空间成员的方法 14.2.5 无名的命名空间 14.2.6 标准命名空间std 14.3 使用早期的函数库 习题 附录A 常用字符与ASCII代码对照表 附录B 运算符与结合性 参考文献 《清华大学计算机系列教材:数据结构(第2版)》第二版在保持原书基本框架和特色的基础上,对主要各章,如第一、二、三、四、六及九章等,作了增删和修改。   《清华大学计算机系列教材:数据结构(第2版)》系统地介绍了各种类型的数据结构和查找、排序的各种方法。对每一种数据结构,除了详细阐述其基本概念和具体实现外,并尽可能对每种操作给出类PASCAL的算法,对查找和排序的各种算法,还着重在时间上作出定量或定性的分析比较。最后一章讨论文件的各种组织方法。   《清华大学计算机系列教材:数据结构(第2版)》概念清楚,内容丰富,并有配套的《数据结构题集》(第二版),既便于教学,又便于自学。   《清华大学计算机系列教材:数据结构(第2版)》可作为计算机类专业和信息类相关专业的教材,也可供从事计算机工程与应用工作的科技工作者参考。 第一章 绪论 1.1 什么是数据结构 1.2 基本概念和术语 1.3 数据结构的发展简史及它在计算机科学中所处的地位 1.4 算法的描述和算法分析 1.4.1 算法的描述 1.4.2 算法设计的要求 1.4.3 算法效率的度量 1.4.4 算法的存储空间需求 第二章 线性表 2.1 线性表的逻辑结构 2.2 线性表的顺序存储结构 2.3 线性表的链式存储结构 2.3.1 线性链表 2.3.2 循环链表 2.3,3 双向链表 2.4 一元多项式的表示及相加 第三章 栈和队列 3.1 栈 3.1.1 抽象数据类型栈的定义 3.1.2 栈的表示和实现 3.2 表达式求值 **3.3 栈与递归过程 3.3.1 递归过程及其实现 3.3.2 递归过程的模拟 3.4 队列 3.4.1 抽象数据类型队列的定义 3.4.2 链队列——队列的链式存储结构 3.4.3 循环队列——队列的顺序存储结构 3.5 离散事件模拟 第四章 串 4.1 串及其操作 4.1.1 串的逻辑结构定义 4.1.2 串的基本操作 4.2 串的存储结构 4.2.1 静态存储结构 4.2.2 动态存储结构 4.3 串基本操作的实现 4.3.1 静态结构存储串时的操作 4.3.2 模式匹配的一种改进算法 4.3.3 堆结构存储串时的操作 4.4 串操作应用举例 4.4.1 文本编辑 **4.4.2 建立词索引表 第五章 数组和广义表 5.1 数组的定义和运算 5.2 数组的顺序存储结构 5.3 矩阵的压缩存储 5.3.1 特殊矩阵 5.3.2 稀疏矩阵 5.4 广义表的定义 5.5 广义表的存储结构 **5.6 m元多项式的表示 **5.7 广义表的递归算法 5.7.1 求广义表的深度 5.7.2 复制广义表 5.7.3 建立广义表的存储结构 第六章 树和二叉树 6.1 树的结构定义和基本操作 6.2 二叉树 6.2.1 定义与基本操作 6.2.2 二叉树的性质 6.2.3 二叉树的存储结构 6.3 遍历二叉树和线索二叉树 6.3.1 遍历二叉树 5.3.2 线索二叉树 6.4 树和森林 6.4.1 树的存储结构 6.4.2 森林与二叉树的转换 6.4.3 树的遍历 **6.5 树与等价问题 6.6 哈夫曼树及其应用 6.6.1 最优二叉树(哈夫曼树) 6.6.2 哈夫曼编码 **6.7 回溯法与树的遍历 **6.8 树的计数 第七章 7.1 的定义和术语 7.2 的存储结构 7.2.1 数组表示法 7.2.2 邻接表 7.2.3 十字链表 7.2.4 邻接多重表 7.3 的遍历 7.3.1 深度优先搜索 7.3.2 广度优先搜索 7.4 的连通性问题 7.4.1 无向的连通分量和生成树 **7.4.2 有向的强连通分量 7.4.3 最小生成树 **7.4.4 关节点和重连通分量 7.5 有向无环及其应用 7.5.1 拓扑排序 7.5.2 关键路径 7.6 最短路径 7.6.1 从某个源点到其余各顶点的最短路径 7.6.2 每一对顶点之间的最短路径 **7.7 二部匹配 第八章 动态存储管理 8.1 概述 8.2 可利用空间表及分配方法 8.3 边界标识法 8.3.1 可利用空间表的结构 8.3.2 分配算法 8.3.3 回收算法 8.4 伙伴系统 8.4.1 可利用空间表的结构 8.4.2 分配算法 8.4.3 回收算法 8.5 无用单元收集 8.6 存储紧缩 第九章 查找 9.1 静态查找表 9.1.1 顺序表的查找 9.1.2 有序表的查找 9.1.3 静态树表的查找 9.1.4 索引顺序表的查找 9.2 动态查找表 9.2.1 二叉排序树和平衡二叉树 9.2.2 B_树和B+树 9.2.3 键树 9.3 哈希表 9.3.1 什么是哈希表 9.3.2 哈希函数的构造方法 9.3.3 处理冲突的方法 9.3.4 哈希表的查找及其分析 第十章 内部排序 10.1 概述 10.2 插入排序 10.2.1 直接插入排序 10.2.2 其它插入排序 10.2.3 希尔排序 10.3 快速排序 10.4 选择排序 10.4.1 简单选择排序 10.4.2 树形选择排序 10.4.3 堆排序 10.5 归并排序 10.6 基数排序 10.6.1 多关键字的排序 10.6.2 链式基数排序 10.7 各种内部排序方法的比较讨论 第十一章 外部排序 11.1 外存信息的存取 11.2 外部排序的方法 11.3 多路平衡归并的实现 11.4 置换-选择排序 **11.5 缓冲区的并行操作处理 11.6 最佳归并树 **11.7 磁带归并排序 11.7.1 平衡归并 11.7.2 多步归并 第十二章 文件 12.1 有关文件的基本概念 12.2 顺序文件 12.3 索引文件 12.4 ISAM文件和VSAM文件 12.4.1 ISAM文件 12.4.2 VSAM文件 12.5 直接存取文件(散列文件) 12.6 多关键字文件 12.6.1 多重表文件 12.6.2 倒排文件 附录一 类PASCAL语言扩充部分的语法 附录二 名词索引 附录三 过程和函数索引 参考书目 《面向对象的C++数据结构算法实现与解析》是采用面向对象的c++语言数据结构教材的学习辅导书,主要内容包括采用c++语言的类、模板、虚函数、友元、友类编写的各种主要数据存储结构的算法、基本操作成员函数、调用这些成员函数的主程序和程序运行结果以及各主要数据存储结构的示。《面向对象的C++数据结构算法实现与解析》还介绍了stl模板的应用。   《面向对象的C++数据结构算法实现与解析》结合存储结构和算法,配合大量的示,对于一些较难理解的算法,还配有文字说明。   《面向对象的C++数据结构算法实现与解析》适用于高等学校学生和自学者,同时也是很好的考研参考书。 第1章 线性表 1.1 顺序存储结构 1.2 链式存储结构 1.2.1 单链表 1.2.2 单循环链表 1.2.3 向循环链表 1.2.4 不设头结点的链表 1.3 静态链表存储结构 第2章 栈和队列 2.1 栈 2.1.1 栈的顺序存储结构 2.1.2 栈的链式存储结构 2.2 栈的应用与递归 2.2.1 数制转换 2.2.2 表达式求值 2.2.3 汉诺塔问题与递归的实现 2.2.4 迷宫问题 2.2.5 皇后问题 2.2.6 马踏棋盘问题 2.2.7 背包问题 2.3 队列 2.3.1 队列的链式存储结构 2.3.2 队列的顺序存储结构 2.4 队列的应用——排队和排队机的模拟 第3章 字符串和矩阵 3.1 字符串 3.1.1 字符串的按需(堆)存储结构 3.1.2 字符串的模式匹配算法 3.2 矩阵 3.2.1 多维数组的顺序存储结构 3.2.2 矩阵的压缩存储 第4章 树与二叉树 4.1 二叉树的顺序存储结构 4.2 二叉树的链式存储结构 4.3 二叉树的遍历 4.4 线索二叉树 4.5 二叉排序树 4.6 平衡二叉树 4.7 红黑树 4.8 伸展树 4.9 树的存储结构 4.10 赫夫曼树和赫夫曼编码 第5章 5.1 的邻接矩阵存储结构 5.2 的邻接表存储结构 5.3 的深度优先遍历和广度优先遍历 5.4 应用 5.4.1 无向的连通分量和生成树 5.4.2 最小生成树 5.4.3 关节点和重连通分量 5.4.4 拓扑排序和关键路径 5.4.5 最短路径 第6章 查找 6.1 静态查找表 6.2 静态树表 6.3 哈希表的插入、删除及查找 6.4 动态查找表 6.4.1 b树 6.4.2 键树 第7章 内部排序 7.1 插入排序 7.2 冒泡排序 7.3 简单选择排序 7.4 希尔排序 7.5 快速排序 7.6 堆排序 7.7 二路归并排序 7.8 静态链表排序 7.9 基数排序 第8章 外部排序 8.1 多路平衡归并 8.2 置换-选择排序 第9章 动态存储管理 9.1 边界标识法 9.2 伙伴系统 参考文献
一、本书的内容 目前,市面上有关计算机算法的书很多,有些叙述严谨但不全面,另外一些则是容量很大但不够严谨。本书将叙述的严谨性以及内容的深度和广度有机地结合了起来。第1版推出后,即在世界范围内受到了广泛的欢迎,被各高等院校用作多种课程的教材和业界的标准参考资料。它深入浅出地介绍了大量的算法及相关的数据结构,以及用于解决一些复杂计算问题的高级策略(如动态规划、贪心算法、平摊分析等),重点在于算法的分析和设计。对于每一个专题,作者都试提供目前最新的研究成果及样例解答,并通过清晰的示来说明算法的执行过程。. 本书是原书的第2版,在第1版的基础之上增加了一些新的内容,涉及算法的作用、概率分析和随机化算法、线性规划,以及对第1版中详尽的、几乎涉及到每一小节的修订。这些修订看似细微,实际上非常重要。书中引入了“循环不变式”,并贯穿始终地用来证明算法的正确性。在不改动数学和分析重点的前提下,作者将第1版中的许多数学基础知识从第一部分移到了附录中。 二、本书的特点 本书在进行算法分析的过程中,保持了很好的数学严谨性。书中的分析和设计可以被具有各种水平的读者所理解。相对来说,每一章都可以作为一个相对独立的单元来教授或学习。书中的算法以英语加伪代码的形式给出,只要有一点程序设计经验的人都能读懂,并可以用任何计算机语言(如C/C++和Java等)方便地实现。在书中,作者将算法的讨论集中在一些比较现代的例子上,它们来自分子生物学(如人类基因项目)、商业和工程等领域。每一小节通常以对相关历史素材的讨论结束,讨论了在每一算法领域的原创研究。 本书的特点可以概括为以下几个方面: 1.概念清晰,广度、深度兼顾。 本书收集了现代计算机常用的数据结构算法,并作了系统而深入的介绍。对涉及的概念和背景知识都作了清晰的阐述,有关的定理给出了完整的证明。 2.“五个一”的描述方法。 本书以相当的深度介绍了许多常用的数据结构和有效的算法。编写上采用了“五个一”,即一章介绍一个算法、一种设计技术、一个应用领域和一个相关话题。.. 3.文并茂,可读性强。 书中的算法均以通俗易懂的语言进行说明,并采用了大量插来说明算法是如何工作的,易于理解。 4.算法的“伪代码”形式简明实用。 书中的算法均以非常简明的“伪代码”形式来设计,可以很容易地把它转化为计算机程序,直接应用。 注重算法设计的效率,对所有的算法进行了仔细、精确的运行时间分析,有利于进一步改进算法。 三、本书的用法 本书对内容进行了精心的设计和安排,尽可能考虑到所有水平的读者。即使是初学计算机算法的人,也可以在本书中找到所需的材料。 每一章都是独立的,读者只需将注意力集中到最感兴趣的章节阅读。 1.适合作为教材或教学参考书。 本书兼顾通用性与系统性,覆盖了许多方面的内容。本书不但阐述通俗、严谨,而且提供了大量练习和思考题。针对每一节的内容,都给出了数量和难度不等的练习题。练习题用于考察对基本内容的掌握程度,思考题有一定的难度,需进行精心的研究,有时还通过思考题介绍一些新的知识。 前言回到顶部↑本书提供了对当代计算机算法研究的一个全面、综合性的介绍。书中给出了多个算法,并对它们进行了较为深入的分析,使得这些算法的设计和分析易于被各个层次的读者所理解。力求在不牺牲分析的深度和数学严密性的前提下,给出深入浅出的说明。. 书中每一章都给出了一个算法、一种算法设计技术、一个应用领域或一个相关的主题。算法是用英语和一种“伪代码”来描述的,任何有一点程序设计经验的人都能看得懂。书中给出了230多幅,说明各个算法的工作过程。我们强调将算法的效率作为一种设计标准,对书中的所有算法,都给出了关于其运行时间的详细分析。 本书主要供本科生和研究生的算法数据结构课程使用。因为书中讨论了算法设计中的工程问题及其数学性质,因此,本书也可以供专业技术人员自学之用。 本书是第2版。在这个版本里,我们对全书进行了更新。所做的改动从新增了若干章,到个别语句的改写。 致使用本书的教师 本书的设计目标是全面、适用于多种用途。它可用于若干课程,从本科生的数据结构课程到研究生的算法课程。由于书中给出的内容比较多,只讲一学期一般讲不完,因此,教师们应该将本书看成是一种“缓存区”或“瑞典式自助餐”,从中挑选出能最好地支持自己希望教授的课程的内容。 教师们会发现,要围绕自己所需的各个章节来组织课程是比较容易的。书中的各章都是相对独立的,因此,你不必担心意想不到的或不必要的各章之间的依赖关系。每一章都是以节为单位,内容由易到难。如果将本书用于本科生的课程,可以选用每一章的前面几节内容;在研究生课程中,则可以完整地讲授每一章。 全书包含920多个练习题和140多个思考题。每一节结束时给出练习题,每一章结束时给出一些
光盘使用说明 <br><br> 清华大学出版社出版<br> _____________________________________________________________________<br> <br> 本盘提供了书中所使用的全部程序文件。为了方便读者使用书中程序,不仅<br>给出了源程序文件,还给出了在Delphi 6.0中生成应用程序的工程文件,和最后生<br>成的可执行文件(.exe文件)。<br> 出版《运筹学算法与编程实践—Delphi实现》一书和配书光盘的宗旨,是改变长<br>期以来运筹学的基本方法与计算机软件使用相分离状况,创建运筹学的理论教学与<br>计算机软件有机结合的新的教学方式。同时,使运筹学的各种优化方法直接为科研<br>和生产服务。 <br>_____________________________________________________________________ <br><br> <br> 使用方法:<br><br> \源程序: 为本书的源码程序。在使用程序之前,需要将光盘上的该程序的所有<br> 文件拷贝到硬盘上,同时去掉其只读属性,然后方可用Delphi 6.0<br> 打开、编译和调试。所有程序均已在Windows 2000的Delphi 6.0环<br> 境下调试通过。<br><br> \系统集成:包含主程序和所有的exe文件、资源文件等。双击Maindex.exe即<br> 可开始运行。*.exe文件的编号对应各章节,以便查找。<br>_____________________________________________________________________ <br> <br> 主要内容:(以书中对应章节排序)<br><br> 线性规划:原始单纯形法、两阶段法、大M法、对偶单纯形法、运输问题;<br> 整数规划:0-1整数规划、指派问题;<br> 非线性规划:黄金分割法、二次插值法、最速下降法、变尺度法;<br> 动态规划:资源分配问题、生产与存储问题、设备更新问题、排序问题;<br> 统筹法:工序自动分级、工序自动编号、通用网络计划技术参数计算;<br> 论: 赋权中各顶点间最短通路值计算、赋权中两顶点间最短通路值的<br> 标号法程序、最大可靠路的计算、求最小支撑树的Kruskal算法、最短<br> 树问题的逐步生长法程序;<br> 排队论: 损失制排队模型、等待制排队模型、混合制排队模型、单通道混合<br> 制排队时间有限模型、多通道混合制排队时间有限模型、闭合式系统;<br> 库存论:经典的经济订货批量模型、允许缺货的经济订贷批量模型、生产批<br> 量模型、有数量折扣模型、随机性模型、(s,S)策略存储模型;<br> 对策论:矩阵对策的最优策略问题、矩阵对策的线性方程组解法、矩阵对策<br> 的线性规划解法;<br> 决策论:风险决策(最大可能法、期望值法、决策树法、矩阵法、多级决策<br> 法)、非确定性决策(乐观法、悲观法、等可能法、α法、折中主义<br> 法、沙万奇法)、贝叶斯决策、决策树决策。
光盘使用说明 <br><br> 清华大学出版社出版<br> _____________________________________________________________________<br> <br> 本盘提供了书中所使用的全部程序文件。为了方便读者使用书中程序,不仅<br>给出了源程序文件,还给出了在Delphi 6.0中生成应用程序的工程文件,和最后生<br>成的可执行文件(.exe文件)。<br> 出版《运筹学算法与编程实践—Delphi实现》一书和配书光盘的宗旨,是改变长<br>期以来运筹学的基本方法与计算机软件使用相分离状况,创建运筹学的理论教学与<br>计算机软件有机结合的新的教学方式。同时,使运筹学的各种优化方法直接为科研<br>和生产服务。 <br>_____________________________________________________________________ <br><br> <br> 使用方法:<br><br> \源程序: 为本书的源码程序。在使用程序之前,需要将光盘上的该程序的所有<br> 文件拷贝到硬盘上,同时去掉其只读属性,然后方可用Delphi 6.0<br> 打开、编译和调试。所有程序均已在Windows 2000的Delphi 6.0环<br> 境下调试通过。<br><br> \系统集成:包含主程序和所有的exe文件、资源文件等。双击Maindex.exe即<br> 可开始运行。*.exe文件的编号对应各章节,以便查找。<br>_____________________________________________________________________ <br> <br> 主要内容:(以书中对应章节排序)<br><br> 线性规划:原始单纯形法、两阶段法、大M法、对偶单纯形法、运输问题;<br> 整数规划:0-1整数规划、指派问题;<br> 非线性规划:黄金分割法、二次插值法、最速下降法、变尺度法;<br> 动态规划:资源分配问题、生产与存储问题、设备更新问题、排序问题;<br> 统筹法:工序自动分级、工序自动编号、通用网络计划技术参数计算;<br> 论: 赋权中各顶点间最短通路值计算、赋权中两顶点间最短通路值的<br> 标号法程序、最大可靠路的计算、求最小支撑树的Kruskal算法、最短<br> 树问题的逐步生长法程序;<br> 排队论: 损失制排队模型、等待制排队模型、混合制排队模型、单通道混合<br> 制排队时间有限模型、多通道混合制排队时间有限模型、闭合式系统;<br> 库存论:经典的经济订货批量模型、允许缺货的经济订贷批量模型、生产批<br> 量模型、有数量折扣模型、随机性模型、(s,S)策略存储模型;<br> 对策论:矩阵对策的最优策略问题、矩阵对策的线性方程组解法、矩阵对策<br> 的线性规划解法;<br> 决策论:风险决策(最大可能法、期望值法、决策树法、矩阵法、多级决策<br> 法)、非确定性决策(乐观法、悲观法、等可能法、α法、折中主义<br> 法、沙万奇法)、贝叶斯决策、决策树决策。
头歌实践平台是一个用于数据分析和可视化的在线平台,可以用来进行数据处理、统计分析和展示。数据结构是数据在计算机内存中的组织方式,而二叉树是一种常用的数据结构之一。二叉树由一组节点组成,每个节点可以有最多两个子节点。最小生成树是在一个连通加权无向中构造的一棵包含所有顶点的子树,且其所有边的权值之和最小。 在头歌实践平台中,可以使用Python语言来实现最小生成树的构建和操作。Python是一种简单易用的高级编程语言,具有丰富的数据处理和算法库,非常适合进行数据结构的实现。 在Python中,可以使用列表、链表等数据结构来表示二叉树的节点和连接关系。可以使用类和对象的方式来定义一个节点类,其中包含节点的值、左子节点和右子节点等属性。通过构建这些节点,可以逐步组成一棵完整的二叉树。 对于最小生成树的构建,可以使用论中的最小生成树算法,如Prim算法或Kruskal算法。通过构建一个无向,并根据权值对边进行排序,可以逐步选择边来构建最小生成树。可以通过循环和条件判断的方式来实现算法的逻辑,通过逐步添加边和节点,最终得到一棵符合最小生成树要求的树结构。 在头歌实践平台中,可以通过输入、输出、形界面等方式来交互,并对通过Python代码实现的数据结构算法进行可视化展示。通过使用头歌实践平台Python编程语言,可以方便地进行数据结构最小生成树实践和学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值