看数据结构写代码(58) B-树

B-树 一种 自平衡的 多路 查找树。它在文件系统里很有用。

一个m阶的B-树,要么是空树,要么是满足这些特性的树。、

1.树 最多 有 m个分支。

2.树的根 最少 两个子树。

3. 树的非终端叶子节点 最少  m/2 向上 取整   个 子树。

4.所有叶子节点 都在 一层。


它的节点 结构:  (N,P0,K1,P1,K2,p2......Kn,Pn)

其中 N 是 节点的 关键字个数,p0~pn 是 指向子树的指针,K1~Kn是关键字


#define M		3 //B树的阶数..

typedef int keyType;

typedef struct BTreeNode{
	int keyNum;//关键字的个数.
	BTreeNode * ptr[M+1];//指针数组,(总比 关键字 多一个).
	keyType key[M+1];//关键字数组,第0个没用,从 第1个开始,
	BTreeNode * parentNode;//节点的父亲..
}*BTree;

根据上面的特性,总结:

1.节点中 分支树,最大为 阶数,最小 为 m/2 向上 取整(根节点最小为2,只有一个根节点 的树 可以没有子树)

2.所有结构中,关键字个数  =  指向子树的指针树 -1,所以关键字 最大 为 M-1,最少 为  上面 所说的 最小值 -1.

3.K1~Kn,顺序排放。

4.假设 k 是 节点的 第 x个 关键字,那么 P(x-1)指向的 子树中的 的 关键字 都比 k小,P(x)指向的子树指向的关键字 都比 k大。


B-树的 查找,分为 两部分,一部分 是顺指针查找节点 ,一部分 是 子 节点里 查找。下面的 search函数 就是 在 子节点里查找 关键字。

struct Result{//查找的结果
	int tag;//0查找失败,1查找成功
	int index;//位置
	BTreeNode * p;//指向查找成功的指针或者插入位置的 指针
};
//查找到:返回k的位置; 没查找到:返回 k值的 搜索指针位置。
int search(BTree t,keyType k){
	if (t != NULL){
		for (int i = 1; i <= t->keyNum; i++){
			if (t->key[i] == k){//找到了返回当前索引
				return i;
			}
			else if(t->key[i] > k){//没找到,返回 前一个位置
				return i-1;
			}
		}
		return t->keyNum;//所有节点 都比 k 小
	}
	return 0;
}
//查找
Result searchBTree(BTree t,keyType k){
	BTree p = t,q = NULL;
	bool isFind = false;
	int index = 0;
	while (p != NULL){
		index = search(p,k);
		if (index >= 1 && p->key[index] == k ){
			isFind = true;
			break;
		}
		else{
			q = p;
			p = p->ptr[index];
		}
	}
	if (isFind){//查找到了
		Result r ={1,index,p};
		return r;
	}
	else{
		Result r ={0,index,q};
		return r;
	}
}

下面 主要 说 B-树的 插入 算法。

1.如果节点 存在,不插入

2.节点不存在,插入 节点

3.如果 插入后, 节点  的 关键字个数 大于 M-1个,则 需要 分裂 ,具体分裂如下:


如果 造成 父节点 关键字个数 超过 M-1,则 需要 分裂。


完整代码如下:

// BTree.cpp : 定义控制台应用程序的入口点。
//B-树:多路自平衡查找树

#include "stdafx.h"
#include <cstdlib>
#include <cmath>
#include "queue.h"
#define M		3 //B树的阶数..

typedef int keyType;

typedef struct BTreeNode{
	int keyNum;//关键字的个数.
	BTreeNode * ptr[M+1];//指针数组,(总比 关键字 多一个).
	keyType key[M+1];//关键字数组,第0个没用,从 第1个开始,
	BTreeNode * parentNode;//节点的父亲..
}*BTree;

//获取一个节点,这样 的 初始化是个 好习惯.
BTreeNode * makeNode(){
	BTreeNode * node = (BTreeNode*)malloc(sizeof(BTreeNode));
	node->parentNode = NULL;
	for (int i = 0; i <= M; i++){
		node->ptr[i] = NULL;
	}
	node->keyNum = 0;
	return node;
}

void initTree(BTree *tree){
	*tree = NULL;
}

struct Result{//查找的结果
	int tag;//0查找失败,1查找成功
	int index;//位置
	BTreeNode * p;//指向查找成功的指针或者插入位置的 指针
};
//查找到:返回k的位置; 没查找到:返回 k值的 搜索指针位置。
int search(BTree t,keyType k){
	if (t != NULL){
		for (int i = 1; i <= t->keyNum; i++){
			if (t->key[i] == k){//找到了返回当前索引
				return i;
			}
			else if(t->key[i] > k){//没找到,返回 前一个位置
				return i-1;
			}
		}
		return t->keyNum;//所有节点 都比 k 小
	}
	return 0;
}
//查找
Result searchBTree(BTree t,keyType k){
	BTree p = t,q = NULL;
	bool isFind = false;
	int index = 0;
	while (p != NULL){
		index = search(p,k);
		if (index >= 1 && p->key[index] == k ){
			isFind = true;
			break;
		}
		else{
			q = p;
			p = p->ptr[index];
		}
	}
	if (isFind){//查找到了
		Result r ={1,index,p};
		return r;
	}
	else{
		Result r ={0,index,q};
		return r;
	}
}
//将 p 插入 到  t->ptr[index+1]
//将 k 插入到 t->key[index+1];
void insert(BTree t,int index,keyType k,BTree p){
	//index 后面的移开
	for (int i = t->keyNum; i > index; i--){
		t->key[i+1] = t->key[i];
		t->ptr[i+1] = t->ptr[i];
	}
	t->key[index+1] = k;
	t->ptr[index +1] = p;
	t->keyNum ++;
}

//将 index 后部分分裂出 一个 新的节点
//指针 复制 :index 到 keyNum
//关键字复制: index +1 到 keyNum
void split(BTree t,int index,BTree * newNode){
	*newNode = makeNode();
	int count = 0;
	for (int i = index; i <= t->keyNum; i++){
		if (i > index){关键字复制: index +1 到 keyNum
			count++;
			(*newNode)->key[count] = t->key[i];//从1 开始.
		}
		BTree child = (*newNode)->ptr[count] = t->ptr[i];
		//忘记写了,需要 把 带走的节点 设置 新的 父节点
		if (child != NULL){
			child->parentNode = *newNode;
		}
		t->ptr[i] = NULL;//设置原有指针为NULL
	}
	//下面两句漏写..
	(*newNode)->parentNode = t->parentNode;
	t->keyNum = index -1;//原节点 数量 减少.
	(*newNode)->keyNum = count;
}
//新的根节点(之前为 空树,或者 分裂出了 一个 头节点)
void newRoot(BTree * t,keyType k,BTree left,BTree right){
	BTree p = *t = makeNode();
	p->key[1] = k;
	p->ptr[0] = left;
	p->ptr[1] = right;
	p->keyNum = 1;
	if (left != NULL){
		left->parentNode = p;
	}
	if (right != NULL)
	{
		right->parentNode = p;
	}
}
//插入
void insertBTree(BTree * t,keyType k){
	Result r = searchBTree(*t,k);
	if (r.tag ==  0){//不存在 ,插入.
		int index = r.index;//插入位置
		BTree p = r.p;//插入节点
		BTree q = NULL;//插入关键字的 右孩子.
		BTree r = NULL;
		bool finished = false;
		while (p != NULL){
			insert(p,index,k,q);
			if (p->keyNum < M){//M阶 的 树,最多 有 M-1个 关键字{
				finished = true;
				break;
			}
			else{//关键字个数 超过M-1个,需要 分裂.
				int mid = (int)ceil(M/2.0);
				split(p,mid,&q);
				k = p->key[mid];//分裂需要插入 到父节点的关键字
				r = p;
				p = p->parentNode;//父节点
				index = search(p,k);//插入到父节点的位置.
			}
		}
		if (finished == false){//空树,或者 根节点的 关键字 大于 M-1
			newRoot(t,k,r,q);
		}
	}
}

//index之后的关键字 和指针左移
void leftMove(BTree p,int index){
	if(index < p->keyNum){
		for (int i = index; i < p->keyNum; i++){
			if (i>= 1){
				p->key[i] = p->key[i+1];
			}
			p->ptr[i] = p->ptr[i+1];
		}
	}
	else{//在最后一个位置,不需要移动
		p->ptr[p->keyNum] = NULL;
	}
	p->keyNum--;
}

//*t 树根,start:搜索开始的节点
bool deleteBTree(BTree * t,BTree start,keyType key){
	Result r = searchBTree(start,key);
	if (r.tag == 1){//找到了
		BTree p = r.p;
		int index = r.index;
		//不是 最底下一层非终端节点,寻找右子树最小节点,替换k值,并删除最小节点
		if (p->ptr[0] != NULL){
			BTree q = p->ptr[index];
			while (q->ptr[0] != NULL){
				q = q->ptr[0];
			}
			p->key[index] = q->key[1];
			return deleteBTree(t,p->ptr[index],q->key[1]);//删除最小节点退出函数
		}
		else// 是 最底下一层 非终端节点.
		{
			//节点最小阶数为 M/2 向上取整,关键字 比 最小阶数 小1
			int min = (int)ceil(M/2.0)-1;
			BTree parent = p->parentNode;
			//是根节点 或者 节点数 大于 min
			if (p->keyNum > min || parent == NULL ){
				leftMove(p,index);//index后面的关键字左移
				if (p->keyNum == 0){//根节点关键字最少为1,空树.
					free(*t);
					*t = NULL;
				}
				return true;
			}
			else if(p->keyNum == min){
				leftMove(p,index);//将删除关键字后面的 左移
				BTree leftBrother = NULL;
				BTree rightBrother = NULL;
				int pIndex = search(parent,key);//寻找节点在 父节点的 位置(查找位置
				if (pIndex>=1){
					leftBrother = parent->ptr[pIndex-1];//左相邻兄弟
				}
				if (pIndex < parent->keyNum){
					rightBrother = parent->ptr[pIndex+1];//右兄弟
				}
				//寻找 是否 有相邻 兄弟 keyNum大于 min的.
				if(leftBrother != NULL && leftBrother->keyNum > min){//左兄弟有空间
					//整个空间 的关键字 右移一个位置
					for (int i = p->keyNum; i >= 1; i--){
						p->key[i+1] = p->key[i];
					}
					p->key[1] = parent->key[pIndex];//父节点关键字下移
					p->keyNum++;
					parent->key[pIndex] = leftBrother->key[leftBrother->keyNum];//将最大值上移到父节点。
					leftBrother->keyNum--;//最终 左兄弟节点的 关键字少了一个,其余没变.
					return true;
				}
				else if (rightBrother != NULL && rightBrother->keyNum > min){//右兄弟有空间
					p->key[p->keyNum+1] = parent->key[pIndex+1];//父节点关键字下移
					p->keyNum++;
					parent->key[pIndex+1] = rightBrother->key[1];//将最小值上移
					leftMove(rightBrother,1);//将 最小值 之后的 左移.
					return true;
				}
				BTree merger = NULL;//合并后的节点
				while (parent != NULL){
					//左右相邻空间都等于 min,需要 删除节点后合并(书中第三种情况)
					if (leftBrother != NULL){
						merger = leftBrother;
						//将节点中其他关键字 和 父节点的第pindex个 复制到左兄弟中
						int lIndex = leftBrother->keyNum+1;//左兄弟下标
						leftBrother->key[lIndex] = parent->key[pIndex];//先复制父节点关键字
						leftMove(parent,pIndex);//父节点关键字后面的左移
						for (int i = 0; i <= p->keyNum; i++){
							if  (i >=1){
								leftBrother->key[lIndex] = p->key[i];
							}
							leftBrother->ptr[lIndex++] = p->ptr[i];
							if (p->ptr[i] != NULL){//设置新的父节点
								p->ptr[i]->parentNode = leftBrother;
							}
						}
						leftBrother->keyNum += p->keyNum + 1;
						free(p);//合并完成删除节点
					}
					else if (rightBrother != NULL){
						merger = rightBrother;
						//加入到右兄弟节点的关键字个数,减去一个关键字,再加上一个父节点关键字
						int addNum = p->keyNum + 1;
						rightBrother->keyNum += addNum;
						//为插入关键字移位
						for (int i = rightBrother->keyNum; i >= 0; i--){
							if (i >= 1){
								rightBrother->key[i+addNum] = rightBrother->key[i];
							}
							rightBrother->ptr[i+addNum] = rightBrother->ptr[i];
						}
						int i = 0;
						for (; i <= p->keyNum; i++){
							if (i >= 1){
								rightBrother->key[i] = p->key[i];
							}
							rightBrother->ptr[i] = p->ptr[i];
							if (p->ptr[i] != NULL){//设置新的父节点
								p->ptr[i]->parentNode = rightBrother;
							}
						}
						rightBrother->key[i] = parent->key[pIndex+1];
						leftMove(parent,pIndex+1);//左移
						free(p);//合并完成,删除节点
					}
					//父节点关键字不足,继续删除父节点,然后合并.
					if (parent->keyNum < min){
						p = parent;
						parent = parent->parentNode;
						pIndex = search(parent,key);//寻找节点在 父节点的 位置(查找位置
						leftBrother = rightBrother = NULL;
						if (pIndex>=1){
							leftBrother = parent->ptr[pIndex-1];//左相邻兄弟
						}
						if (pIndex < parent->keyNum){
							rightBrother = parent->ptr[pIndex+1];//右兄弟
						}
					}
					else if (parent->keyNum > M-1){//合并后的关键字超过 M-1,需要分裂
						BTree newNode = NULL,r = NULL;
						bool finished = false;
						p = parent;
						keyType k = 0;
						while (p != NULL){
							int mid = (int)ceil(M/2.0);
							split(p,mid,&newNode);
							k = p->key[mid];//分裂需要插入 到父节点的关键字
							r = p;
							p = p->parentNode;
							if (p != NULL){
								index = search(p,k);//插入到父节点的位置.
								insert(p,index,k,newNode);
								if (p->keyNum < M){//M阶 的 树,最多 有 M-1个 关键字{
									finished = true;
									break;
								}
							}
						}
						if (finished == false){//空树,或者 根节点的 关键字 大于 M-1
							newRoot(t,k,r,newNode);
						}
						return true;
					}
				}
				//根节点最少一个,当为0时,将合并的节点设置为新的 根节点。
				if (p->keyNum == 0){
					free(p);
					*t = merger;
					return true;
				}
			}
			else{//error
				printf("------------ERROR--------------\n");
			}
		}
	}
	return false;//没找到
}

//层序遍历
void levelOrderTraverse(BTree tree){
	if (tree != NULL){
		LinkQueue queue;
		queueInit(&queue);
		enqueue(&queue,tree);
		int count = 1;
		int nextCount = 0;
		int level = 1;
		printf("-----------层序遍历--------------\n");
		while (!queueEmpty(queue)){
			printf("第%d层数据:",level);
			for (int i = 0; i < count; i++){
				BTree front;
				dequeue(&queue,&front);
				for (int j= 0; j <= front->keyNum; j++){
					if (j >=1){
						printf("%d\t",front->key[j]);
					}
					if (front->ptr[j] != NULL){
						enqueue(&queue,front->ptr[j]);
					}
					nextCount++;
				}
				printf("------");
			}
			printf("\n");
			count = nextCount;
			nextCount = 0;
			level ++;
		}
		queueDestory(&queue);
		printf("\n");
	}
}


int _tmain(int argc, _TCHAR* argv[])
{
	BTree tree;
	initTree(&tree);
	int array [11] = {22,11,55,66,77,33,44,99,88,22,33};
	for (int i = 0; i < 11; i++){
		insertBTree(&tree,array[i]);
		//printf("-----插入%d后------------\n",array[i]);
		//levelOrderTraverse(tree);
	}
	levelOrderTraverse(tree);
	return 0;
}

其中包含了部分不正确的 B-树 删除代码,在处理 下面 这个问题时,不正确。书中 也没提到 这种情况。希望 以后 完善。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是数据结构里面的伪代码的c实现 1.1 数组和字符串 2 1.1.1 一维数组的倒置 2 范例1-1 一维数组的倒置 2 ∷相关函数:fun函数 1.1.2 一维数组应用 3 范例1-2 一维数组应用 3 1.1.3 一维数组的高级应用 5 范例1-3 一维数组的高级应用 5 1.1.4 显示杨辉三角 7 范例1-4 显示杨辉三角 7 ∷相关函数:c函数 8 1.1.5 魔方阵 9 范例1-5 魔方阵 9 1.1.6 三维数组的表示 14 范例1-6 三维数组的表示 14 ∷相关函数:InitArray函数 1.1.7 多项式的数组表示 17 范例1-7 多项式数组的表示 17 1.1.8 查找矩阵的马鞍点 19 范例1-8 查找矩阵的马鞍点 19 ∷相关函数:Get_Saddle函数 1.1.9 对角矩阵建立 21 范例1-9 对角矩阵建立 21 ∷相关函数:Store函数 1.1.10 三对角矩阵的建立 22 范例1-10 三对角矩阵的建立 22 ∷相关函数:Store函数 1.1.11 三角矩阵建立 24 范例1-11 三角矩阵建立 24 ∷相关函数:Store函数 1.1.12 对称矩阵的建立 25 范例1-12 对称矩阵的建立 25 ∷相关函数:store函数 1.1.13 字符串长度的计算 28 范例1-13 字符串长度的计算 28 ∷相关函数:strlen函数 1.1.14 字符串的复制 29 范例1-14 字符串的复制 29 ∷相关函数:strcpy函数 1.1.15 字符串的替换 31 范例1-15 字符串的替换 31 ∷相关函数:strrep函数 1.1.16 字符串的删除 33 范例1-16 字符串的删除 33 ∷相关函数:strdel函数 1.1.17 字符串的比较 35 范例1-17 字符串的比较 35 ∷相关函数:strcmp函数 1.1.18 字符串的抽取 36 范例1-18 字符串的抽取 36 ∷相关函数:substr函数 1.1.19 字符串的分割 38 范例1-19 字符串的分割 38 ∷相关函数:partition函数 1.1.20 字符串的插入 40 范例1-20 字符串的插入 40 ∷相关函数:insert函数 1.1.21 字符串的匹配 42 范例1-21 字符串的匹配 42 ∷相关函数:nfind函数 1.1.22 字符串的合并 43 范例1-22 字符串的合并 43 ∷相关函数:catstr函数 1.1.23 文本编辑 45 范例1-23 文本编辑 45 ∷相关函数:StrAssign函数 1.2 栈和队列 54 1.2.1 用数组仿真堆栈 54 范例1-24 用数组仿真堆栈 54 ∷相关函数:push函数 pop函数 1.2.2 用链表仿真堆栈 57 范例1-25 用链表仿真堆栈 57 ∷相关函数:push函数 pop函数 1.2.3 顺序栈公用 59 范例1-26 顺序栈公用 59 ∷相关函数:push函数 pop函数 1.2.4 进制转换问题 61 范例1-27 进制转换问题 61 ∷相关函数:MultiBaseOutput函数 1.2.5 顺序队列操作 64 范例1-28 顺序队列操作 64 ∷相关函数:push函数 pop函数 1.2.6 循环队列 66 范例1-29 循环队列 66 ∷相关函数:EnQueue函数 DeQueue函数 1.2.7 链队列的入队、出队 69 范例1-30 链队列入队、出队 69 ∷相关函数:push函数 pop函数 1.2.8 舞伴问题 71 范例1-31 舞伴问题 71 ∷相关函数:EnQueue函数 DeQueue函数 DancePartner函数 1.3 链表 75 1.3.1 头插法建立单链表 75 范例1-32 头插法建立单链表 75 ∷相关函数:createlist函数 1.3.2 限制链表长度建立单链表 77 范例1-33 限制链表长度建立长单链表 77 ∷相关函数:createlist函数 1.3.3 尾插法建立单链表 79 范例1-34 尾插法建立单链表 79 ∷相关函数:createlist函数 1.3.4 按序号查找单链表 80 范例1-35 按序号查找单链表 80 ∷相关函数:getnode函数 1.3.5 按查找单链表 82 范例1-36 按查找单链表 82 ∷相关函数:locatenode函数 1.3.6 链表的插入 84 范例1-37 链表的插入 84 ∷相关函数:insertnode函数 1.3.7 链表的删除 86 范例1-38 链表的删除 86 ∷相关函数:deletelist函数 1.3.8 归并两个单链表 88 范例1-39 归并两个单链表 88 ∷相关函数:concatenate函数 1.3.9 动态堆栈 90 范例1-40 动态堆栈 90 ∷相关函数:push函数 Pop函数 1.3.10 动态队列 93 范例1-41 动态队列 93 ∷相关函数:Enqueue函数 1.3.11 初始化单循环链表 95 范例1-42 初始化单循环链表 95 ∷相关函数:ListLength_CL函数 1.3.12 查询元素的前驱和后继 98 范例1-43 查询元素的前驱和后继 98 ∷相关函数:PriorElem_CL函数 NextElem_CL函数 1.3.13 单循环链表中元素的删除 101 范例1-44 单循环链表中元素的删除 101 ∷相关函数:ListDelete_CL函数 1.3.14 单循环链表的清除和销毁 107 范例1-45 单循环链表的清除和销毁 107 ∷相关函数:DestroyList函数 1.3.15 仅设表尾指针循环链表的合并 110 范例1-46 仅设表尾指针循环链表的合并 110 ∷相关函数:MergeList_CL函数 1.3.16 正序输出双向链表 113 范例1-47 正序输出双向链表 113 ∷相关函数:ListInsert函数 ListTraverse函数 1.3.17 逆向输出双向链表 116 范例1-48 三角矩阵建立 116 ∷相关函数:ListTraverseBack函数 1.3.18 删除双向链表中的节点 121 范例1-49 删除双向链表中的节点 121 ∷相关函数:ListDelete函数 1.3.19 双向链表的元素个数 124 范例1-50 双向链表的元素个数 124 ∷相关函数:ListLength函数 1.3.20 判断双向链表是否为空 126 范例1-51 判断双向链表是否为空 126 ∷相关函数:ListEmpty函数 1.3.21 双向链表元素的查询 129 范例1-52 双向链表元素的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷相关函数:erase函数 1.4 和二叉 141 1.4.1 获得二叉的深度和根(顺序结构) 141 范例1-55 获得二叉的深度和根 141 ∷相关函数:BiTreeDepth函数 Root函数 1.4.2 获得二叉的深度和根(链表结构) 144 范例1-56 获得二叉的深度和根 144 ∷相关函数:BiTreeDepth函数 Root函数 1.4.3 插入顺序结构) 147 范例1-57 插入 147 ∷相关函数:InsertChild函数 1.4.4 节点的修改(顺序结构) 150 范例1-58 节点的修改 150 ∷相关函数:Assign函数 1.4.5 节点的修改(链式结构) 154 范例1-59 节点的修改 154 ∷相关函数:Assign函数 1.4.6 双亲、孩子和兄弟节点的查询(顺序结构) 158 范例1-60 双亲、孩子和兄弟节点的查询 158 ∷相关函数:Parent函数 LeftChild函数 RightChild函数 LeftSibling函数 RightSibling函数 1.4.7 双亲、孩子和兄弟节点的查询(链式结构) 162 范例1-61 双亲、孩子和兄弟节点的查询 162 ∷相关函数:Parent函数 LeftChild函数 RightChild函数 LeftSibling函数 RightSibling函数 1.4.8 中序遍历二叉顺序结构) 169 范例1-62 中序遍历二叉 169 ∷相关函数:InOrderTraverse函数 1.4.9 中序遍历二叉(链式结构) 171 范例1-63 中序遍历二叉 171 ∷相关函数:InOrderTraverse函数 1.4.10 中序非递归遍历二叉(链式结构)(1) 174 范例1-64 中序非递归遍历二叉 174 ∷相关函数:InOrderTraverse函数 1.4.11 中序非递归遍历二叉(链式结构)(2) 177 范例1-65 中序非递归遍历二叉 177 ∷相关函数:InOrderTraverse2函数 1.4.12 后序遍历二叉顺序结构) 180 范例1-66 后序遍历二叉 180 ∷相关函数:PostOrderTraverse函数 1.4.13 后序遍历二叉(链式结构) 183 范例1-67 后序遍历二叉 183 ∷相关函数:PostOrderTraverse函数 1.4.14 层次遍历二叉顺序结构) 186 范例1-68 层次遍历二叉 186 ∷相关函数:LevelOrderTraverse函数 1.4.15 层次遍历二叉(链式结构) 188 范例1-68 层次遍历二叉 188 ∷相关函数:LevelOrderTraverse函数 1.4.16 的合并 191 范例1-70 的合并 191 ∷相关函数:Find函数 Union函数 1.4.17 的二叉链表存储的基本操作 193 范例1-71 的二叉链表存储的基本操作 193 ∷相关函数:LevelOrderTraverse函数 1.4.18 二叉的三叉链表存储的基本操作 201 范例1-72 二叉的三叉链表存储表示 201 ∷相关函数:CreateBiTree函数 1.4.19 二叉的二叉线索存储的基本操作 212 范例1-73 二叉的二叉线索存储 212 ∷相关函数:CreateBiThrTree函数 1.4.20 的双亲表存储的基本操作 215 范例1-74 的双亲表存储的基本操作 215 ∷相关函数:CreateTree函数 1.4.21 哈夫曼编码(1) 223 范例1-75 哈夫曼编码(1) 223 ∷相关函数:HuffmanCoding函数 1.4.22 哈夫曼编码(2) 226 范例1-76 哈夫曼编码(2) 226 ∷相关函数:HuffmanCoding函数 1.5 排序 229 1.5.1 直接插入排序 229 范例1-77 直接插入排序 229 ∷相关函数:InsertSort函数 1.5.2 折半插入排序(顺序结构) 231 范例1-78 折半插入排序(顺序结构) 231 ∷相关函数:BInsertSort函数 1.5.3 2—路插入排序(顺序结构) 233 范例1-79 2—路插入排序(顺序结构) 233 ∷相关函数:P2_InsertSort函数 1.5.4 折半插入排序(链式结构) 235 范例1-80 折半插入排序(链式结构) 235 ∷相关函数:Arrange函数 1.5.5 2—路插入排序(链式结构) 238 范例1-81 2—路插入排序(链式结构) 238 ∷相关函数:Rearrange函数 1.5.6 希尔排序 241 范例1-82 希尔排序 241 ∷相关函数:ShellSort函数 1.5.7 冒泡排序 243 范例1-83 冒泡排序 243 ∷相关函数:bubble_sort函数 1.5.8 一趟快速排序 246 范例1-84 一趟快速排序 246 ∷相关函数:QSort函数 1.5.9 一趟快速排序的改进算法 248 范例1-85 一趟快速排序的改进算法 248 ∷相关函数:QuickSort函数 1.5.10 简单选择排序 250 范例1-86 简单选择排序 250 ∷相关函数:SelectSort函数 1.5.11 箱子排序 252 范例1-87 箱子排序 252 ∷相关函数:sort函数 1.5.12 型选择排序 254 范例1-88 型选择排序 254 ∷相关函数:TreeSort函数 1.5.13 堆排序 256 范例1-89 堆排序 256 ∷相关函数:HeapSort函数 1.5.14 归并排序 258 范例1-90 归并排序 258 ∷相关函数:MergeSort函数 1.5.15 多路平衡归并排序 260 范例1-91 多路平衡归并排序 260 ∷相关函数:K_Merge函数 1.5.16 置换—选择排序 265 范例1-92 置换—选择排序 265 ∷相关函数:Replace_Selection函数 1.5.17 文件的归并 269 范例1-93 文件的归并 269 ∷相关函数:K_Merge函数 1.6 查找 272 1.6.1 顺序表的查找 273 范例1-94 顺序表的查找 273 ∷相关函数:Search_Seq函数 1.6.2 静态表的查找 276 范例1-95 静态表的查找 276 ∷相关函数:Search_SOSTree函数 1.6.3 二叉排序的基本操作 280 范例1-96 二叉排序的基本操作 280 ∷相关函数:InsertBST函数 1.6.4 平衡二叉的基本操作 285 范例1-97 平衡二叉的基本操作 285 ∷相关函数:SearchBST函数 1.6.5 B的基本操作 290 范例1-98 B的基本操作 290 ∷相关函数:SearchBTree函数 1.6.6 按关键字符串的遍历双链键 295 范例1-99 按关键字符串遍历双链键 295 ∷相关函数:SearchDLTree函数 1.6.7 按关键字符串的遍历Trie 301 范例1-100 按关键字符串遍历Trie 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 范例1-102 图的邻接矩阵存储表示 ∷相关函数:CreateFAG函数 CreateDG函数 1.7.2 图的邻接表存储表示 324 范例1-103 图的邻接表存储表示 324 ∷相关函数:CreateFAG函数 1.7.3 有向图的十字链表存储表示 335 范例1-104 有向图的十字链表存储表示 335 ∷相关函数:CreateDG函数 1.7.4 无向图的邻接多重表存储表示 344 范例1-105 无向图的邻接多重表存储表示 344 ∷相关函数:CreateGraph函数 1.7.5 最小生成 355 范例1-106 最小生成 355 ∷相关函数:MiniSpanTree_PRIM函数 1.7.6 关节点和重连通分量 359 范例1-107 关节点和重连通分量 359 ∷相关函数:FindArticul函数 1.7.7 拓扑排序 366 范例1-108 拓扑排序 366 ∷相关函数:TopologicalSort函数 1.7.8 关键路径 374 范例1-109 关键路径 374 ∷相关函数:CriticalPath函数 1.7.9 最短路径 383 范例1-110 最短路径 383 ∷相关函数:ShortestPath_DIJ函数 1.7.10 每一对顶点之间的最短路径 387 范例1-111 每一对顶点之间的最短路径 387 ∷相关函数:ShortestPath_FLOYD函数
1.1 数组和字符串 2 1.1.1 一维数组的倒置 2 范例1-1 一维数组的倒置 2 ∷相关函数:fun函数 1.1.2 一维数组应用 3 范例1-2 一维数组应用 3 1.1.3 一维数组的高级应用 5 范例1-3 一维数组的高级应用 5 1.1.4 显示杨辉三角 7 范例1-4 显示杨辉三角 7 ∷相关函数:c函数 8 1.1.5 魔方阵 9 范例1-5 魔方阵 9 1.1.6 三维数组的表示 14 范例1-6 三维数组的表示 14 ∷相关函数:InitArray函数 1.1.7 多项式的数组表示 17 范例1-7 多项式数组的表示 17 1.1.8 查找矩阵的马鞍点 19 范例1-8 查找矩阵的马鞍点 19 ∷相关函数:Get_Saddle函数 1.1.9 对角矩阵建立 21 范例1-9 对角矩阵建立 21 ∷相关函数:Store函数 1.1.10 三对角矩阵的建立 22 范例1-10 三对角矩阵的建立 22 ∷相关函数:Store函数 1.1.11 三角矩阵建立 24 范例1-11 三角矩阵建立 24 ∷相关函数:Store函数 1.1.12 对称矩阵的建立 25 范例1-12 对称矩阵的建立 25 ∷相关函数:store函数 1.1.13 字符串长度的计算 28 范例1-13 字符串长度的计算 28 ∷相关函数:strlen函数 1.1.14 字符串的复制 29 范例1-14 字符串的复制 29 ∷相关函数:strcpy函数 1.1.15 字符串的替换 31 范例1-15 字符串的替换 31 ∷相关函数:strrep函数 1.1.16 字符串的删除 33 范例1-16 字符串的删除 33 ∷相关函数:strdel函数 1.1.17 字符串的比较 35 范例1-17 字符串的比较 35 ∷相关函数:strcmp函数 1.1.18 字符串的抽取 36 范例1-18 字符串的抽取 36 ∷相关函数:substr函数 1.1.19 字符串的分割 38 范例1-19 字符串的分割 38 ∷相关函数:partition函数 1.1.20 字符串的插入 40 范例1-20 字符串的插入 40 ∷相关函数:insert函数 1.1.21 字符串的匹配 42 范例1-21 字符串的匹配 42 ∷相关函数:nfind函数 1.1.22 字符串的合并 43 范例1-22 字符串的合并 43 ∷相关函数:catstr函数 1.1.23 文本编辑 45 范例1-23 文本编辑 45 ∷相关函数:StrAssign函数 1.2 栈和队列 54 1.2.1 用数组仿真堆栈 54 范例1-24 用数组仿真堆栈 54 ∷相关函数:push函数 pop函数 1.2.2 用链表仿真堆栈 57 范例1-25 用链表仿真堆栈 57 ∷相关函数:push函数 pop函数 1.2.3 顺序栈公用 59 范例1-26 顺序栈公用 59 ∷相关函数:push函数 pop函数 1.2.4 进制转换问题 61 范例1-27 进制转换问题 61 ∷相关函数:MultiBaseOutput函数 1.2.5 顺序队列操作 64 范例1-28 顺序队列操作 64 ∷相关函数:push函数 pop函数 1.2.6 循环队列 66 范例1-29 循环队列 66 ∷相关函数:EnQueue函数 DeQueue函数 1.2.7 链队列的入队、出队 69 范例1-30 链队列入队、出队 69 ∷相关函数:push函数 pop函数 1.2.8 舞伴问题 71 范例1-31 舞伴问题 71 ∷相关函数:EnQueue函数 DeQueue函数 DancePartner函数 1.3 链表 75 1.3.1 头插法建立单链表 75 范例1-32 头插法建立单链表 75 ∷相关函数:createlist函数 1.3.2 限制链表长度建立单链表 77 范例1-33 限制链表长度建立长单链表 77 ∷相关函数:createlist函数 1.3.3 尾插法建立单链表 79 范例1-34 尾插法建立单链表 79 ∷相关函数:createlist函数 1.3.4 按序号查找单链表 80 范例1-35 按序号查找单链表 80 ∷相关函数:getnode函数 1.3.5 按查找单链表 82 范例1-36 按查找单链表 82 ∷相关函数:locatenode函数 1.3.6 链表的插入 84 范例1-37 链表的插入 84 ∷相关函数:insertnode函数 1.3.7 链表的删除 86 范例1-38 链表的删除 86 ∷相关函数:deletelist函数 1.3.8 归并两个单链表 88 范例1-39 归并两个单链表 88 ∷相关函数:concatenate函数 1.3.9 动态堆栈 90 范例1-40
1. 对一个算法的评价,不包括如下( )方面的内容。 A.健壮性和可读性 B.并行性 C.正确性 D.时空复杂度 2. 在带有头结点的单链表HL中,要向表头插入一个由指针p指向的结点,则执行( )。 A. p->next=HL->next; HL->next=p; B. p->next=HL; HL=p; C. p->next=HL; p=HL; D. HL=p; p->next=HL; 3. 对线性表,在下列哪种情况下应当采用链表表示?( ) A.经常需要随机地存取元素 B.经常需要进行插入和删除操作 C.表中元素需要占据一片连续的存储空间 D.表中元素的个数不变 4. 一个栈的输入序列为1 2 3,则下列序列中不可能是栈的输出序列的是( ) A. 2 3 1 B. 3 2 1 C. 3 1 2 D. 1 2 3 5. 采用开放定址法处理散列表的冲突时,其平均查找长度( )。 A.低于链接法处理冲突 B. 高于链接法处理冲突 C.与链接法处理冲突相同 D.高于二分查找 6. 若需要利用形参直接访问实参时,应将形参变量说明为( )参数。 A. B.函数 C.指针 D.引用 7. 在稀疏矩阵的带行指针向量的链接存储中,每个单链表中的结点都具有相同的( )。 A.行号 B.列号 C.元素 D.非零元素个数 8. 快速排序在最坏情况下的时间复杂度为( )。 A.O(log2n) B.O(nlog2n) C.0(n) D.0(n2) 9. 从二叉搜索中查找一个元素时,其时间复杂度大致为( )。 A. O(n) B. O(1) C. O(log2n) D. O(n2) 10. 栈和队列的共同特点是( )。 A.只允许在端点处插入和删除元素 B.都是先进后出 C.都是先进先出 D.没有共同点 11. 用链接方式存储的队列,在进行插入运算时( ). A. 仅修改头指针   B. 头、尾指针都要修改 C. 仅修改尾指针 D.头、尾指针可能都要修改 12. 以下数据结构中哪一个是非线性结构?( ) A. 队列    B. 栈 C. 线性表    D. 二叉 13. 最适合用来表示( )。 A.有序数据元素 B.无序数据元素 C.元素之间具有分支层次关系的数据 D.元素之间无联系的数据 14. 二叉的第k层的结点数最多为( ). A.2k-1 B.2K+1 C.2K-1    D. 2k+1 15. 若有18个元素的有序表存放在一维数组A[19]中,第一个元素放A[1]中,现进行二分查找,则查找A[3]的比较序列的下标依次为( ) A. 1,2,3 B. 9,5,2,3 C. 9,5,3 D. 9,4,2,3 16. 对n个记录的文件进行快速排序,所需要的辅助存储空间大致为 A. O(1)   B. O(n)   C. O(1og2n) D. O(n2) 17. 对于线性表(7,34,55,25,64,46,20,10)进行散列存储时,若选用H(K)=K %9作为散列函数,则散列地址为1的元素有( )个, A.1 B.2 C.3 D.4 18. 设有6个结点的无向图,该图至少应有( )条边才能确保是一个连通图。 A.5 B.6 C.7 D.8 19.设数组data[m]作为循环队列SQ的存储空间,front为队头指针,rear为队尾指针,则执行出队操作后其头指针front为( ) A.front=front+1 B.front=(front+1)%(m-1) C.front=(front-1)%m D.front=(front+1)%m 20.如下陈述中正确的是( ) A.串是一种特殊的线性表 B.串的长度必须大于零 C.串中元素只能是字母 D.空串就是空白串 21.设一组初始记录关键字序列为(345,253,674,924,627),则用基数排序需要进行( )趟的分配和回收才能使得初始关键字序列变成有序序列。 (A) 3 (B) 4 (C) 5 (D) 8 22.设用链表作为栈的存储结构则退栈操作( )。 (A) 必须判别栈是否为满 (B) 必须判别栈是否为空 (C) 判别栈元素的类型 (D) 对栈不作任何判别 23.下列四种排序中( )的空间复杂度最大。 (A) 快速排序 (B) 冒泡排序 (C) 希尔排序 (D) 堆 24.数据的最小单位是( )。 (A) 数据项 (B) 数据类型 (C) 数据元素 (D) 数据变量 25.设一组初始记录关键字序列为(50,40,95,20,15,7060,45),则以增量d=4的一趟希尔排序结束后前4条记录关键字为( )。 (A) 40,5020,95 (B) 15,40,6020 (C) 15,20,40,45 (D) 45,40,15,20 26.设一组初始记录关键字序列为(25,50,15,35,80,85,20,40,36,70),其中含有5个长度为2的有序子表,则用归并排序的方法对该记录关键字序列进行一趟归并后的结果为( )。 (A) 15,25,35,5020,40,80,85,36,70 (B) 15,25,35,508020,85,40,70,36 (C) 15,25,35,5080,85,20,36,40,70 (D) 15,25,35,508020,36,40,70,85 27. 设一组权集合W={2,3,4,5,6},则由该权集合构造的哈夫曼中带权路径长度之和为( )。 (A) 20 (B) 30 (C) 40 (D) 45 28下面程序的时间复杂为( )。 for(i=1,s=0; i<=n; i++) { t=1; for(j=1;j<=i;j++) t=t*j;s=s+t; } A.O(n) B.O(n2) C.O(n3) D.O(n4) 29.递归过程中必定用到的数据结构是( )。 A.循环队列 B.堆栈 C.二叉 D.散列 30.设按照从上到下、从左到右的顺序从1开始对完全二叉进行顺序编号,则编号为i结点的左孩子结点的编号为( )。 (A) 2i+1 (B) 2i (C) i/2 (D) 2i-1 31.设一组初始记录关键字序列为(13,18,24,35,47,50,62,83,90,115,134),则利用二分法查找关键字90需要比较的关键字个数为( )。 (A) 1 (B) 2 (C) 3 (D) 4 32.设指针变量top指向当前链式栈的栈顶,则删除栈顶元素的操作序列为( )。 (A) top=top+1; (B) top=top-1; (C) top->next=top; (D) top=top->next; 33. 字符串的长度是指( )。 (A) 串中不同字符的个数 (B) 串中不同字母的个数 (C) 串中所含字符的个数 (D) 串中不同数字的个数 34. 队列是一种( )的线性表。 (A) 先进先出 (B) 先进后出 (C) 只能插入 (D) 只能删除 35.设散列表中有m个存储单元,散列函数H(key)= key % p,则p最好选择( )。 (A) 小于等于m的最大奇数 (B) 小于等于m的最大素数 (C) 小于等于m的最大偶数 (D) 小于等于m的最大合数 36.如下代码段输出的结果是( )。 String s1 = "abc"; String s2 = new String(s1); System.out.println(s1 == s2 + ","); System.out.println(s1.equals(s2)); A.true,true B.false,false C.true,false D.false ,true 37.二叉有( )种不同的基本形态。 A.3 B.4 C.5 D.6 38.设一组初始记录关键字序列为(Q,H,C,Y,P,A,M,S,R,D,F,X),则按字母升序的第一趟冒泡排序结束后的结果是( )。 (A) F,H,C,D,P,A,M,Q,R,S,Y,X (B) P,A,C,S,Q,D,F,X,R,H,M,Y (C) A,D,C,R,F,Q,M,S,Y,P,H,X (D) H,C,Q,P,A,M,S,R,D,F,X,Y 39.设顺序循环队列Q[0:M-1]的头指针和尾指针分别为F和R,头指针F总是指向队头元素的前一位置,尾指针R总是指向队尾元素的当前位置,则该循环队列中的元素个数为(C )。 (A) R-F (B) F-R (C) (R-F+M)%M (D) (F-R+M)%M 40.设某棵二叉的中序遍历序列为ABCD,前序遍历序列为CABD,则后序遍历该二叉得到序列为( )。 (A) BADC (B) BCDA (C) CDAB (D) CBDA 41.设某完全无向图中有n个顶点,则该完全无向图中有( )条边。 (A) n(n-1)/2 (B) n(n-1) (C) n2 (D) n2-1 42.设某棵二叉中有2000个结点,则该二叉的最小高度为( )。 (A) 9 (B) 10 (C) 11 (D) 12 43.设一组初始关键字记录关键字为(20,15,14,18,21,36,40,10),则以20为基准记录的一趟快速排序结束后的结果为( A )。 (A) 10,15,14,1820,36,40,21 (B) 10,15,14,1820,40,36,21 (C) 10,15,14,2018,40,36,2l (D) 15,10,14,1820,36,40,21 44.设一组初始记录关键字序列为(345,253,674,924,627),则用基数排序需要进行()趟的分配和回收才能使得初始关键字序列变成有序序列。 (A) 3 (B) 4 (C) 5 (D) 8 45.设有n个关键字具有相同的Hash函数,则用线性探测法把这n个关键字映射到Hash表中需要做( )次线性探测。 A.2 B.n(n+1) C.n(n+1)/2 D.n(n-1)/2 46.设一组初始记录关键字序列为(13,18,24,35,47,50,62,83,90,115,134),则利用二分法查找关键字90需要比较的关键字个数为( )。 A.1 B.2 C.3 D.4 47.设二叉的先序遍历序列和后序遍历序列正好相反,则该二叉满足的条件是( )。 A.空或只有一个结点 B.高度等于其结点数 C.任一结点无左孩子 D.任一结点无右孩子 48.设有n个待排序的记录关键字,则在堆排序中需要()个辅助记录单元。 (A) 1 (B) n (C) nlog2n (D) n2 49.下面关于线性表的叙述错误的是( )。 (A) 线性表采用顺序存储必须占用一片连续的存储空间 (B) 线性表采用链式存储不必占用一片连续的存储空间 (C) 线性表采用链式存储便于插入和删除操作的实现 (D) 线性表采用顺序存储便于插入和删除操作的实现 50.将10阶对称矩阵压缩存储到一维数组A中,则数组A的长度最少为( )。 (A) 100 (B) 40 (C) 55 (D) 80 51数据结构是指数据及其相互之间的______________。当结点之间存在M对N(M:N)的联系时,称这种结构为_____________________。 52.一组初始记录关键字序列为(Q,H,C,Y,P,A,M,S,R,D,F,X),则按字母升序的第一趟冒泡排序结束后的结果是 。 53.队列的插入操作是在队列的___尾______进行,删除操作是在队列的____首______进行。54.根据搜索方法的不同,图的遍历有 和 两种。 55.堆栈的操作特点是 。 56. 若对一棵完全二叉从0开始进行结点的编号,并按此编号把它顺序存储到一维数组A中,即编号为0的结点存储到A[0]中。其余类推,则A[ i ]元素的左孩子元素为________,右孩子元素为_______________,双亲元素为____________。 57. 快速排序算法的平均时间复杂度为____________,直接插入排序算法的平均时间复杂度为___________。 58.对于一个长度为n的单链存储的线性表,在表头插入元素的时间复杂度为_________,在表尾插入元素的时间复杂度为____________。 59.一棵高度为5的二叉中最少含有______个结点,最多含有_____个结点。 11.对于给定的若干个元素,可以构造出的逻辑结构有 结构, 结构和 结构三种。 60.后缀算式9 2 3 +- 10 2 / -的为__________。中缀算式(3+4X)-2Y/3对应的后缀算式为_______________________________。 61.设完全二叉顺序存储结构中存储数据ABCDE,要求给出该二叉的链式存储结构并给出该二叉的前序、中序和后序遍历序列。 62.设给定一个集合W=(3,5,7,9,11),要求根据给定的权集合构造一棵哈夫曼并计算哈夫曼的带权路径长度WPL。 63.设一组初始记录关键字序列为(19,21,16,5,18,23),要求给出以19为基准的一趟快速排序结果以及第2趟直接选择排序后的结果。 64..线性表的存储结构有哪两种,各有何特点? 65.在顺序循环队列中,什么是假溢出?请指出解决假溢出的常见方法。 66.阅读下面的算法: LinkList mynote(LinkList L) {//L是不带头结点的单链表的头指针 if(L&&L->next){ q=L;L=L->next;p=L; S1: while(p->next) p=p->next; S2: p->next=q;q->next=NULL; } return L; } 语句S1和语句组S2的功能是什么? 67.已知一个无向图的顶点集为{a, b, c, d, e} ,其邻接矩阵如下所示 (1)画出该图的图形; (2)根据邻接矩阵从顶点a出发进行深度优先遍历和广度优先遍历,出相应的遍历序列。 68.已知关键字序列为{8,17,26,32,40,72,87,99},采用折半查找算法,给定70,35时分别与哪些元素比较?画出相应的二叉判定 69. 设散列表的长度为8,散列函数H(k)=k mod 7,初始记录关键字序列为(25,31,8,27,13,68),要求分别计算出用线性探测法和链地址法作为解决冲突方法的平均查找长度。 70.对于KMP算法,模式串中每个字符的最大真子串构成一个数组,定义为模式串的next[j]函数。next[j]函数定义如下: Max{k|0<k<j且“t0t1…tk-1”=“tj-ktj-k+1…tj-1”} 当此集合非空时 next[j]= 0 其他情况 -1 当j=0 计算t=“abcabaa”的next[j],要求出具体的推算步骤。
谭浩强教授,我国著名计算机教育专家。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函数(格式输入函数)
好的,以下是可以回答的Python代码: ```python import requests from bs4 import BeautifulSoup import csv url = "https://bj.58.com/ershoufang/" params = { "PGTID": "0d100000-0000-18d3-3a3b-6c133d6d2fbc", "ClickID": 1 } res = requests.get(url, params=params) res.encoding = "utf-8" soup = BeautifulSoup(res.text, "html.parser") with open("house_info.csv", "w", newline="", encoding="utf-8") as csvfile: writer = csv.writer(csvfile) writer.writerow(["标题", "面积", "均价", "总价", "标签", "用途", "户型", "装修情况", "朝向"]) for house in soup.select(".list > li"): title = house.select_one(".title > a").string.strip() area = house.select_one(".area > div > div:first-child").string.strip() unit_price = house.select_one(".unit > span:first-child").string.strip() total_price = house.select_one(".total > span").string.strip() tags = "/".join([tag.string.strip() for tag in house.select(".baseinfo > div:first-child > a")]) usage = house.select_one(".baseinfo > div:first-child > span").string.strip() layout = house.select_one(".baseinfo > div:nth-child(2) > span:nth-child(1)").string.strip() decoration = house.select_one(".baseinfo > div:nth-child(2) > span:nth-child(2)").string.strip() orientation = house.select_one(".baseinfo > div:nth-child(2) > span:nth-child(3)").string.strip() writer.writerow([title, area, unit_price, total_price, tags, usage, layout, decoration, orientation]) print("数据已存储为 house_info.csv 文件。") ``` 注意:此代码的运行结果仅供参考,使用前需仿照运行环境和数据结构进行调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值