数据结构算法设计复习题|自用

38 阅读10分钟

链式存储结构二叉树

typedef struct node {
	int data;
	struct node *lchild, *rchild;
}bitree;

void swap(bitree *T)

链表

typedef struct node {
	int data;
	struct node* next;
}Node, *LinkList;

p = (LinkList)malloc(sizeof(Node));

LinkList addin(LinkList A)

顺序表

struct record {
	int key;
	int others;
};
int bisearch(struct record r[], int k) {
r[mid].key == k;
}

//顺序栈 
typedef struct {
	int data[MAXSIZE];
	int top;
}SeqStack;
//链栈
typedef struct Snode {
	int data;
	struct Snode *next;
}*LinkStack;

1.在单链表中删除值相同的多余结点的算法

	LinkList p, q, s;
	for(p = T; p != NULL; p = p->next) {
		for(q = p->next, s = q; q != NULL) {
			if(p->data == q->data ){
				s->next = q->next;
				free(q);
				q = s->next;
			}
			else {
				s = q;
				q = q->next;
			}
		}
	}
}

2.在链式存储结构上建立一棵二叉排序树

void bstinsert(bitree *&bt, int key) {
	if(bt == NULL) {
		bt = (bitree*)malloc(sizeof(bitree));
		bt->key = key;
		bt->lchild = bt->rchild = NULL;
	}
	else if(bt->key > key) bstinsert(bt->lchild, key);
	else bstinsert(bt->rchild, key);
}

void createbsttree(bitree *bt) {
	int i;
	for(i = 1; i <= n ; i++)bstinsert(bt, random(100));
}

3.判断两个二叉树是否相同

void createbsttree(bitree *bt) {
	int i;
	for(i = 1; i <= n ; i++)bstinsert(bt, random(100));
}

int judgebitree(bitree *bt1, bitree *bt2) {
	if(bt1 == NULL && bt2 == NULL)return 1;
	else if(bt1 == NULL || bt2 == NULL || bt1->data != bt2->data)return 0;
	else return(judgebitree(bt1->lchild, bt2->lchild) * judgebitree(bt1->rchild, bt2->rchild))
}

4.两个单链表合并

void mergelklist(LinkList ha, LinkList hb, LinkList &hc) {
	LinkList s = hc = NULL;
	if(ha != NULL && hb != NULL) {
		if(ha->data < hb->data) {
			if(s == NULL) {
				hc = s = ha;
			}
			else {
				s->next = ha;
				s = ha;
			}
			ha = ha->next;
		}
		else {
			if(s == NULL) {
				hc = s = hb;
			}
			else {
				s->next = hb;
				s = hb;
			}
			hb = hb->next;
		}	
		}
	if(ha == NULL) s->next = hb;
	else s->next = ha;
}

5.判断二叉树是否为二叉排序树

void inorder(bitree *bt) {
	if(bt != NULL) {
		inorder(bt->lchild);
		if(minnum > bt->key) flag = 0;
		//若当前节点的值小于之前遍历到的最小值 minnum,则将 flag 设置为 0,表示该二叉树不是按照升序排列的
		minnum = bt->key;//更新 minnum 的值为当前节点的值
		inorder(bt->rchild);
	}
}

6.在链式结构上实现简单选择排序算法

void simple(LinkList &h) {
	LinkList p, q, s;
	int min, t;
	if(h == NULL || h->next == NULL) return;
	for(q = h, q != NULL;q = q->next ) {
		min = q->data;
		s = q;
		for(p = q->next; p != NULL; p = p->next) {
			if(min > p->data){
				min = p->data;
				s = p;
			}
			if(s != q) { 
				t = s->data;
				s->data = q->data;
				q->data = t;
		}
	}
}
} 

7.求结点在二叉排序树中层次

void level(bitree *bt, int x) {
	int lev = 0;
	if(bt != NULL) {
		lev++;
		if(bt->key == x)return;
		else if(bt->key > x) level(bt->lchild, x);
		else level(bt->rchild, x);
	}
}

8.将所有奇数移到所有偶数之前

void quickpass(int r[], int s, int t) {
	//对r[]数组中从索引s到索引t的元素进行排序
	int i = s, j = t, x = r[s];
	while(i < j) {
		while(i < j && r[j]%2 == 0) j = j-1;
		if(i < j){
			r[i] = r[j];
			i = i+1;
		}
		while(i < j && r[i]%2 == 1) i = i+1;
		if(i < j) {
			r[j] = r[i];
			j = j-1;
		}
	}
	r[i] = x;
}

9.计判断单链表中元素是否是递增

int inser(LinkList h) {
	if(h == NULL || h->next == NULL) return 1;
	for(q = h, p = h->next; q != NULL; q = p, p = p->next) {
		if(q->data > p->data) return 0;
	}
	return 1;
} 

10.计在二叉排序树上查找结点 X

bitree *bstsearch(bitree *t, int key) {
	bitree *p = t;
	while(p != 0){
		if(p->data == key) return p;
		else if(p->key > key) p = p->lchild;
		else p = p->rchild;
	}
	return 0;
} 

11.顺序表删除第i个元素

int DeleteList(SqList& L, int i) {
	int j;
	if (i < 1 || i > L.length) {
		printf("不存在第i个元素");
		return 0;//要删除的元素不存在
	}
	for (j = i + 1; j < L.length + 1; j++) {
		L.elem[j - 2] = L.elem[j - 1];//将ai+1~an顺序上移,从而删除ai,注意第i个元素是a[i-1]
	}
	L.length--;//修改表长
	return 1;//删除成功
}

12.二叉树层次遍历

#define MAX 100
void ss(BiTree T) {
	BiTree Q[MAX], p;
	int f = 0, r = 0;//首尾指针 
	if(T == NULL) return;
	Q[r++] = T;
	while(f != r) {
		p = Q[f++];
		printf("%c", p->data);
		if(p->lchild) {
			if(r >= MAX) {
				printf("overflow");
				exit(0);
			}
			Q[r++] = p->lchild;
		}
		if(p->rchild) {
			if(r >= MAX) {
				printf("overflow");
				exit(0);
			}
			Q[r++] = p->rchild;
		}
	}
} 

//这种算法会导致假溢出,所以接下来用循环队列 

#define MAX 1000

//二叉链表 
typedef struct BiTNode {
	int data;
	struct BiTNode *lchild, rchild;//左右子树根结点地址 
}BiTNode, *BiTree;

//顺序栈
 typedef struct {
 	BiTree data[MAX];
 	int top;
 }SeqStack;

//先序非递归遍历二叉树
//访问根结点后,在访问左子树前,应保存其非空右子树 
void PreorderTraverse(BiTree T) {
	SeqStack s;
	s.top = -1;
	BiTree p = (BiTNode*)malloc(sizeof(BiTNode));
        //也可以用BiTree p = (BiTree)malloc(sizeof(BiTNode));
	p = T;
	while(p) {
		printf("%c", p->data);//访问p结点
		if(p->rchild) {//若p有右孩子 
			if(s.top == MAX-1) exit(0);//栈满了,错误 
			else s.data[++s.top] = p->rchild;//栈没满,则右孩子入栈
			p = p->lchild;//访问p的左孩子 
		} 
	//下一轮,若p的左孩子为空,则不再进行while,访问栈顶元素,相当于回溯 
	if(s.top != -1) p = s.data[s.top--];//若栈不空,则栈顶元素出栈 
	}
} 

//中序非递归遍历二叉树
//访问根结点的左子树前,应保存其根结点,以便访问根和根的右子树 
void InorderTraverse(BiTree T) {
	SeqStack s;
	s.top = -1;
	BiTree p = (BiTNode*)malloc(sizeof(BiTNode));
	p = T;
	while(p || (s.top != MAX - 1)) {
		while(p) { 
			if(s.top == MAX-1) exit(0);//栈满了,错误 
			s.data[++s.top] = p;//栈没满,则p入栈
			p = p->lchild;//访问p的左孩子 
		} 
	if(s.top != -1) {
		p = s.data[s.top--];//若栈不空,则栈顶元素出栈 
		printf("%c", p->data);//访问p结点
		p = p->rchild;
	}
} 

//后序非递归遍历二叉树
//访问根结点的左子树前,应保存其根结点,以便访问根的右子树和根 
void InorderTraverse(BiTree T) {
	SeqStack s;
	s.top = -1;
	BiTree p = (BiTNode*)malloc(sizeof(BiTNode));
	p = T;
	while(p || (s.top != MAX - 1)) {
		while(p) { 
			if(s.top == MAX-1) exit(0);//栈满了,错误 
			s.data[++s.top] = p;//栈没满,则p入栈
			p = p->lchild;//访问p的左孩子 
		} 
	if(s.top != -1) {
		p = s.data[s.top--];//若栈不空,则栈顶元素出栈 
		printf("%c", p->data);//访问p结点
		p = p->rchild;
	}
} 
 

深搜

//图的邻接表存储 
typedef struct ArcNode {
	int vex;//该弧所指向的顶点的位置
	struct ArcNode *link;//指向下一条弧的指针
	InfoType *info;//该弧的相关信息的指针 
}ArcNode;//单链表节点类型

typedef struct VNode {
	int data;//顶点信息
	ArcNode *firstarc;//指向第一条依附该顶点的弧 
}VNode;//数组元素类型

typedef struct {
	VNode arc[MAXSIZE];
	int vexnum, arcnum;//顶点数,边数
	int kind;//图的类型,有向or无向 
}Graphs; 

void DFSTraverse(Graphs G) {
	//对图G作深度优先遍历
	for(v = 0; v < G.vexnum; ++v) 
		visited[v] = 0;//访问标志数组初始化,0代表未被访问
	for(v = 0; v < G.vexnum; ++v) 
		if(!visited[v]) DFS(G,v);//对未访问的顶点调用DFS 
}
void DFS(Graphs G, int v) {
	printf("%d\t", v);
	visited[v] = 1;
	p = G.arc[v].firstarc;
	while(p) {
		w = p->vex;
		if(visited[w] == 0) DFS(G, w);
		p = p->link;
	}
} 

宽搜

void BFSTraverse(Graphs G) {
	//对图G作广度优先遍历
	for(v = 0; v < G.vexnum; ++v) 
		visited[v] = 0;//访问标志数组初始化,0代表未被访问
	for(v = 0; v < G.vexnum; ++v) 
		if(!visited[v]) BFS(G,v);//对未访问的顶点调用BFS 
}
void BFS(Graphs G, int v) {
	int Q[MAX], f = 0, r = 0;
	printf("%d\t", v);
	visited[v] = 1;//访问v 
	Q[r++] = v;//v入队 
	while(f <r) {//当队列不空时 
		x = Q[f++]; //队头x出队 
		p = G.arc[x].firstarc;//x的邻接点p 
		while(p) {//当p存在时 
			w = p->vex;//访问x的邻接结点 
			if(visited[w] == 0) {//若w未访问过 
				visited[w] = 1;//则访问 
				printf("%d\t", w);
				Q[r++] = w;//并入队 
				p = p->link;//求下一个邻接点 
			}
		}
	} 
	
	while(p) {
		w = p->vex;
		if(visited[w] == 0) DFS(G, w);
		p = p->link;
	}
} 

二叉排序树,查找、插入

//存储结构为二叉链表
typedef struct NODE {
	int key;
	struct NODE *lc, *rc;
}BiNode, *BiTree; 

Bitree Search(BiNode *t, int x) {
	BiTree p;
	p = t;
	while(p != NULL) {
		if(x == p->key) return p;//若x等于根结点的关键字,则查找成功
		if(x < p->key p = p->lc;//小于则在左子树上找 
		else p = p->rc;//大于则在右子树找 
	}
	return p;//函数返回查找结果,没找到为空指针! 
}

int Insert(Bitree &t, int x) {
	BiTree q, p, s;
	q = NULL;//q为p的双亲节点,根节点无双亲节点 
	p = t;//p为正在查看的节点,初始从根节点t开始 
	while(p != NULL) {
		if(x == p->key) return 0;//在当前二叉树中找到x,不用插入
		q = p;//更新双亲节点 
		if(x < p->key) p= p->lc;//如果x比当前节点小,则进入左子树
		else p = p->rc; //如果x比当前节点大,则进入右子树 
	}
	s = (BiTree)malloc(sizeof(Binode));//没找到x,做插入,申请节点空间
	s->key = x; s->lc = NULL; s->rc = NULL;//s存放x,设为叶节点
	if(q == NULL) t = s; //若原先的二叉树是一棵空树,新插入的x对应的节点s为插入后二叉树的根节点
	else if(x < q->key) q->lc = s;//若x小于其双亲节点,则作为其左孩子
	else q->rc = s;//若x大于其双亲节点,则作为其右孩子
	return 1; 
} 

排序

插入排序

//待排序的数据元素从下标为1的数组元素开始存放。下标0处为哨兵项
void insertSort(SqList L) {
	int i, j;
	for(i = 2; i <= L.length; i++)//从第二个数据开始插入,n = L.length
		if(L.r[i].key < L.r[i-1].key) {//第i个数据比前面已经有序的i-1个数据最大的小
			L.r[0] = L.r[i];//将第i个数据放入哨兵位置
			L[i] = L.r[i-1];
			for(j = i-2; L.r[0].key < L.r[j].key; --j)///L.r[0]存放的是此次要插入的第i个数据
				L.r[j+1] = L.r[j];
				L.r[j+1] = L.r[0];
		}
}

二分插入排序

void BinsertSort(SqList &L) {
	int i, low, high, mid;
	for(i = 2; i <= L.length; i++)
		if(L.r[i].key < L.r[i-1].key) {
			L.r[0] = L.r[i];
			low = 1;
			high = i-1;
			while(low <= high) {
				mid = (low +high)/2;
				if(L.r[0].key < L.r[mid].key)high = mid - 1;
				else low = mid +1; 
			}
			for(j = i-1; k >= high + 1; j--)
				L.r[j+1] = L.r[j];
			L.r[high + 1] = L.r[0];
		}
} 

快速排序

int partition(SqList L, int l, int h) {
	L.r[0] = L.r[l];//取待排序的第一个数据元素为基准放到L.r[0]
	//原来的L.r[l]初始相当于空着 
	//从后面开始找 
	while(l < h) {//一趟快排结束的条件是左右边界重合
		//若右边界大于基准,则右边界左移一位
		while((l<h) && (L.r[h].key >= L.r[0].key)) 
			h--;
                        //右边界小于基准,则把右边的大数放到前面的空位
		if(l < h) {
			L.r[l] = L. r[h];
			l++;
		}
		//若左边界小于基准,则左边界右移一位
		while((l<h) && (L.r[l].key <= L.r[0].key)) 
			l++;
                        //若大于,则把左边的小数移到后面的空里
		if(l < h) {
			L.r[h] = L. r[l];
			h--;
		}
		//l=h跳出循环 
		L.r[l] = L.r[0];//把基准元素放到这个重合处的空里 
		return l;//返回基准的位置 
			
		
	}
} 

//递归,结束的条件是待排序的数据元素个数小于等于1 
void QSort(SqList &L. int l, int h) {
	int t;
	if(l<h) { //待排序的数据有2个或2个以上才进行排序操作
		t = partition(L, l, h);//调用一趟快排,t为返回的基准的位置
		QSort(L, l, t-1);//对比基准小的子序列继续进行快速排序
		QSort(L, t+1, h);//对比基准大的子序列继续进行快速排序
}
} 

冒泡排序

void qppx(SqList &L) {
	int i, j, k;
	j = 1;
	k = 1;
	//共有n-1趟排序:j从1到length-1 
	while((j < L.length) && (k > 0)) {
		k = 0;
		//第j趟要比较n-j次:i从1到n-j 
		for(i = 1; i <= L.length-j; i++)
			if(L.r[i+1].key < L.r[i].key]) {//出现逆序,利用辅助空间r[0]交换 
				L.r[0] = L.r[i];
				L.r[i] = L.r[i+1];
				L.r[i+1] = L.r[0];
				k++;//k记录每一趟排序中发生的交换次数,交换则+1 
			}
			j++;} 
	}

简单选择

void SelectSort(SqList &L) {
	int i, j, k;
	for(i = 1; i < L.length; i++) {//进行n-1趟排序 
		k = i;//第i趟时,初始设当前最小的数据为第k=i个数据元素
		for(j = i+1; j <= L.length; ++j)
		//从第i+1个到第n个,依次和当前最小的第k个数据元素比较,若比第k个还小,则更新k
			if(L.r[j].key < L.r[k].key)
				k = j;//标记j为当前最小的元素
                        //如果现在最小的元素不是i,就把最小元素交换到i上
			if(k != i) {
				//交换借用额外的辅助空间L.r[0], O(1) 
				L.r[0] = L.r[i];
				L.r[i] = L.r[k];
				L.r[k] = L.r[0];
			}
		} 
	}
} 

计算有向图的出入度

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100

typedef struct ArcNode {
    int vex; // 该弧所指向的顶点的位置
    struct ArcNode *link; // 指向下一条弧的指针
} ArcNode; // 单链表节点类型

typedef struct VNode {
    int data; // 顶点信息
    ArcNode *firstarc; // 指向第一条依附该顶点的弧 
} VNode; // 数组元素类型

typedef struct {
    VNode arc[MAXSIZE];
    int vexnum, arcnum; // 顶点数,边数
    int kind; // 图的类型,有向or无向 
} Graphs;

// 计算顶点的入度和出度
void calcDegree(Graphs *G, int numb, int *in_degree, int *out_degree) {
    // 初始化入度和出度
    *in_degree = *out_degree = 0;
    
    // 遍历邻接表,计算入度和出度
    for (int i = 0; i < G->vexnum; i++) {
        ArcNode *p = G->arc[i].firstarc;
        while (p) {
            if (p->vex == numb) {
                // 找到一条以numb为终点的弧,增加入度
                (*in_degree)++;
            }
            p = p->link;
        }
        if (i == numb) {
            // 当前顶点为numb,统计出度
            p = G->arc[i].firstarc;
            while (p) {
                (*out_degree)++;
                p = p->link;
            }
        }
    }
}