数据结构代码基础60题

一、顺序表

顺序表结构体定义
typedef struct{
	int data[maxsize];
	int length;
}SqList;

1.顺序表递增有序,插入元素x,仍递增有序
void insert(SqList &L, int x){
	for(int i=0; i<L.length; i++){
		if(L.data[i] >= x){
			for(int j=L.length; j>i; j--){
				L.data[j] = L.data[j-1];
			}
			L.data[i] = x;
			L.length++;
			break;
		}
	}
}

2.用顺序表最后一个元素覆盖整个顺序表中最小元素,并返回该最小元素
int cover(SqList &L){
	int min = 0;
	for(int i=1; i<L.length; i++){
		if(L.data[i] < L.data[min]){
			min = i;
		}
	}
	int minvalue = L.data[min];
	L.data[min] = L.data[length-1];
	L.length--;
	return minvalue;
}

3.将顺序表中的元素逆置
void reserve(SqList &L){
	int temp;
	for(int i=0; i<L.length/2; i++){
		temp = L.data[i];
		L.data[i] = L.data[length-1-i];
		L.data[length-1-i] = temp;
	}
}

4.删除顺序表中所有值为x的元素(喝前摇一摇,考前看一看)
思想:删除顺序表中所有值为x的元素等价于保留顺序表中所有值不为x的元素
void delete(SqList &L, int x){
	int k = 0;
	for(int i=0; i<L.length; i++){
		if(L.data[i] != x){
			L.data[k++] = L.data[i];
		}
	}
	L.length = k;
}

5.从顺序表中删除给定值在s到t之间(包含s和t)的所有元素
void delete(SqList &L, int s, int t){
	int k = 0;
	for(int i=0; i<L.length; i++){
		if(L.data[i]<s || L.data[i]>t){
			L.data[k] = L.data[i];
			k++;
		}
	}
	L.length = k;
}

6.从有序表中删除所有值重复的元素(喝前摇一摇,考前看一看)
思想:从有序表中删除所有值重复的元素等价于保留第一个不重复的元素
void delete(SqList &L){
	int i,j;
	for(i=0;j=1; j<L.length; j++){
		if(L.data[i] != L.data[j]){
			L.data[++i] = L.data[j];
		}
	}
	L.length = i+1;
}

7.两个递增有序表合并成一个递增有序表(喝前摇一摇,考前看一看)
void union(SqList L1, SqList L2, SqList &L3){
	int i=0; j=0; k=0;
	while(i<L1.length && j<L2.length){
		if(L1.data[i] < L2.data[j]){
			L3.data[k++] = L1.data[i++];
		}else {
			L3.data[k++] = L2.data[j++];
		}
	}
	while(i<L1.length){
		L3.data[k++] = L1.data[i++];
	}
	while(j<L2.length){
		L3.data[k++] = L2.data[j++];
	}
	L3.length = k;
}

8.设计一个时间上尽可能高效的算法,找出数组中未出现的最小正整数(喝前摇一摇,考前看一看)
int min(int A[], int n){
	int *B = new int[n+1];
	int i;
	for(i=0; i<n+1; i++){
		B[i] = 0;
	}//将B数组中的值全部默认为0
	for(i=0; i<n+1; i++){
		if(A[i]>0 && A[i]<=n){
			B[A[i]] = A[i];
		}
	}//将B数组的下标与A数组的值对应
	for(i=1; i<n+1; i++){
		if(B[i] == 0){
			break;
		}
	}
	delete[] B;
	return i;	
}

二、链表

链表结构体定义
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode, *LinkList;

1.设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
void delete(LNode *&L, int x){
	LNode *p;
	if(L == NULL){
		return;
	}
	if(L->data == x){
		p = L;
		L = L->next;
		free(p);
		delete(L, x);
	}else{
		delete(L->next, x);
	}
}

2.删除带头结点单链表中所有值为x的结点
void delete(LNode *&L, int x){
	LNode *p = L;
	while(p->next != NULL){
		if(p->next->data == x){
			LNode *q = p->next;
			p->next = q->next;
			free(q);
		}else{
			p = p->next;
		}
	}
}

3.删除单链表中第一个值为x的元素
int delete(LNode *&L, int x){
	LNode *p = L;
	while(p->next != NULL){
		if(p->next->data == x){
			LNode *q = p->next;
			p->next = q->next;
			free(q);
			break;
		}else{
			p = p->next;
		}
	}
}

4.试编写算法将单链表就地逆置
思路:头插法
void reserve(LNode *&L){
	LNode *p = L->next;
	LNode *r;
	L->next = NULL;
	while(p != NULL){
		r = p->next;
		p->next = L->next;
		L->next = p;
		p = r;
	}
}

5.试编写在带头结点的单链表L中删除最小值点的高效算法(已知最小值唯一)
void delete(LNode *L){//minp指向最小值的前驱
	LNode *p = L;
	LNode *minp = L;
	while(p->next != NULL){
		if(p->next->data < minp->next->data){
			minp = p;
		}
		p = p->next;
	}
	LNode *q = minp->next;
	minp->next = q->next;
	free(q);
}

6.试编写在不带头结点的单链表L中删除最小值点的高效算法(已知最小值唯一)(喝前摇一摇,考前看一看)
void delete(LNode *L){//minp指向最小值
	LNode *minp = L;
	LNode *p = L->next;
	while(p != NULL){
		if(p->data < minp->data){
			minp = p;
		}
		p = p->next;
	}
	if(L == minp){
		L = L->next;
		free(L);
		return;
	}//第一个结点是最小值点时特殊处理
	p = L;
	while(p->next != minp){
		p = p->next;
	}//找最小值点的前驱
	p->next = minp->next;
	free(minp);
}

7.给定一个单链表,按递增排序输出单链表中各结点的数据元素,并释放结点所占空间
void print(LNode *L){
	while(L->next != NULL){
		LNode *p = L;
		LNode *minp = L;
		while(p->next != NULL){
			if(p->next->data < minp->next->data){
				minp = p;
			}
			p = p->next;
		}
		cout << minp->next->data << "";
		LNode *q = minp->next;
		minp->next = q->next;
		free(q);
	}
	free(L);
}

8.将一个带头结点的单链表A分解成两个带头结点的单链表A和B,使A中含奇数位置元素,B中含偶数位置元素,且相对位置不变
LNode *separate(LNode *&A){
	LNode *p = A->next;//p指向A的首结点
	LNode *r1 = A;//r1用来操作拆分后的A链表
	A->next = NULL:
	LNode *B = (LinkList)malloc(sizeof(LNode));
	LNode *r2 = B;//r2用来操作拆分后的B链表
	B->next = NULL;
	LNode *r;
	int i = 1;//i用来区分链表的奇数位置和偶数位置
	while(p != NULL){
		if(i%2 != 0){
			r = p->next;//r用来记录p的后继结点
			p->next = r1->next;
			r1->next = p;
			r1 = r1->next;
			p = r;
		}else{
			r = p->next;
			p->next = r2->next;
			r2->next = p;
			r2 = r2->next;
			p = r;
		}
		i++;
	}
	return B;
}

9.删除递增链表中重复的元素
void delete(LNode *&L){
	LNode *p = L->next;//p指向首结点
	while(p != NULL){
		LNode *pre = p;//pre指向q的前驱结点
		LNode *q = p->next;//q用来遍历p的后续结点
		while(q != NULL){
			if(q->data == p->data){
				pre->next = q->next;
				free(q);
				q = pre->next;
			}else{
				pre= pre->next;
				q = q->next;
			}
		}
		p = p->next;
	}
}

10.两个递增有序的单链表,设计算法将两个链表合并成一个非递减有序的链表(喝前摇一摇,考前看一看)
void union(LNode *&A, LNode *&B){
	LNode *p = A->next;//p指向A的首结点
	A->next = NULL;
	LNode *r = A;//用来操作合并后的新链表
	LNode *q = B->next;//q指向B的首结点
	LNode *r1
	while(p != NULL && q != NULL){
		if(p->data < q->data){
			r1 = p->next;//r1用来指向p的后继结点
			p->next = r->next;
			r->next = p;
			r = r->next;
			p = r1;
		}else{
			r1 = q->next;
			q->next = r->next;
			r->next = q;
			r = r->next;
			q = r1;
		}
	}
	if(p != NULL){
		r->next = p;
	}
	if(q != NULL){
		r->next = q;
	}
}

 11.A,B两个单链表递增有序,从A,B中找出公共元素产生单链表C,要求不破坏A,B结点
LNode *common(LNode *A, LNode *B){
	LNode *p = A->next;//p指向A的首结点
	LNode *q = B->next;//q指向B的首结点
	LNode *C = (LinkList)malloc(sizeof(LNode));
	C->next = NULL;
	LNode *r = C;//r用来操作C链表
	LNode s;//s表示新生成的结点
	while(p!=NULL && q!=NULL){
		if(p->data < q->data){
			p = p->next;
		}else if(q->data < p->data){
			q = q->next;
		}else{
			s = (LNode *)malloc(sizeof(LNode));
			s->data = p->data;
			r->next = s;
			r = s;
			p = p->next;
			q = q->next;
		}
	}
	r->next = NULL;
	return C;
}

12.查找单链表中倒数第k个结点,若成功,则输出该结点的data,并返回1,否则返回0
int find(LNode *L, int k){
	LNode *p = L->next;//p指向L的首结点
	LNode *q = L->next;//q指向L的首结点
	int i = 0;//用来寻找p后的第k个结点
	while(p!=NULL && i<k){//q指向p后的第k的结点
		q = q->next;
		i++;
	}
	if(i != k){
		return 0;
	}
	while(q != NULL){//当q走到表尾是p正好指向倒数第k个结点
		p = p->next;
		q = q->next;
	}
	cout << p->data << "";
	return 1;
} 

13.用单链表保存m个整数,并且|data|<=n,要求设计时间复杂度尽可能高效的算法,对于data绝对值相等的点,仅保留第一次出现的点(喝前摇一摇,考前看一看)
void func(LNode *&L, int n){
	LNode *p = L;
	int *A = new int[n+1];//新建一个长度为n+1的辅助数组A
	for(int i=0 ;i<n+1; i++){//初始化辅助数组A
		A[i] = 0;
	}
	int m;
	LNode *q;
	while(p->next != NULL){
		m = abs(p->next->data);
		if(A[m] == 0){
			A[m] = 1;
			p = p->next;
		}else{
			q = p->next;
			p->next = q->next;
			free(q);
		}
	}
	free(A);
}

14.判断带头结点的循环双链表是否对称
bool func(LNode *L){
	LNode *p = L->next;
	LNode *q = L->prior;
	while(p!=q && q->next!=p){
		if(p->data != q->data){
			return false;
		}
		p = p->next;
		q = q->prior;
	}
	return true;
}

15.有两个循环单链表,链表头指针分别为h1,h2,试编写函数将h2链表接到h1之后,要求链接后仍保持循环链表形式(喝前摇一摇,考前看一看)
void link(LNode *&h1, LNode *&h2){
	LNode *p = h1;
	LNode *q = h2;
	while(p->next != h1){
		p = p->next;
	}
	while(q->next != h2){
		q = q->next;
	}
	q->next = h1;
	p->next = h2;
}

16.设有一个带头结点的循环单链表,其结点值为正整数,设计算法反复找出链表内最小值并不断输出,并将结点从链表中删除,直到链表为空,再删除表头结点
void delete(LNode *L){
	while(L->next != L){
		LNode *p = L;
		LNode *minp = L
		while(p->next != L){
			if(p->next->data < minp->next->data){
				minp = p;
			}
		}
		cout << minp->next->data << "";
		LNode *q = minp->next;
		minp->next = q->next;
		free(q);
	}
	free(L);
}

17.判断单链表是否有环(喝前摇一摇,考前看一看)
int func(LNode *L){
	LNode *fast = L;
	LNode *slow = L;
	while(fast && fast->next){
		slow = slow->next;
		fast = fast->next->next;
		if(slow == fast){
			return 1;
		}
	}
	return 0;
}

三、栈和队列

栈的结构体
typedef struct{
	char data[maxsize];
	int top;
}Stack;

队列的结构体
typedef strcut{
	int data[maxsize];
	int front, rear;
}Queue;

1.S是一个空栈,Q是一个队列,编写算法使得队列中元素逆置(喝前摇一摇,考前看一看)
void reserve(Stack &S, Queue &Q){
	while(Q.front != Q.rear){
		push(S, dequeue(Q));
	}//出队入栈
	while(S.top != -1){
		enqueue(Q, pop(S));
	}//出栈入队
}

2.判断单链表的全部n个字符是否中心对称
bool func(LNode *L){
	Stack S;
	int top = -1;
	LNode *p = L->next;
	while(p != NULL){
		S.data[++S.top] = p->data;
		p = p->next;
	}
	p = L->next;
	while(S.top != -1){
		if(p->data != S.data[S.top--]){
			return false;
		}
	}
	return true;
}

3.两个栈S1,S2都采用顺序存储,并共享一个存储区[0,...,maxsize-1]。采用栈顶相向,迎面增长的存储方式,设计S1,S2入栈和出栈操作(喝前摇一摇,考前看一看)
bool push(Stack &S, int i, int x){//入栈
	if(i<0 || i>1){
		return false;
	}
	if(s.top[1]-s.top[0] == 1){
		return false;
	}
	if(i == 0){
		S.data[++S.top[0]] = x;
	}else if(i == 1){
		S.data[--S.top[1]] = x;
	}
	return true;
}
bool pop(Stack &S, int i){//出栈
	if(i<0 || i>1){
		return false;
	}
	if(i == 0){
		if(S.top[0] == -1){
			return false;
		}else{
			return S.data[S.top[0]--]
		}
	}else if(i == 1){
		if(S.top[1] == maxsize){
			return false;
		}else{
			S.data[S.top[1]++];
		}
	}
	return true;
}

4.判断一个表达式中括号是否配对(假设只包含圆括号)(喝前摇一摇,考前看一看)
bool func(Stack S, String str){
	int i = 0;
	while(str[i] != '\0'){ //‘\0’是字符串结束标志位
		if(str[i]=='('){
			push(S,'(');
		}
		if(str[i]==')'){
			if(pop(S)!='('){
				return false;
			}
		}
		i++;
	}
	if(S.top == -1){
		return true;
	}else{
		return false;
	}
}

四、树

树的结构体
typedef struct BTNode{
	char data;
	struct BTNode *lchild, *rchild;
}BTNode, *BiTree;

1.计算二叉树中所有结点个数
void count(BTNode *p, int &n){
	if(p != NULL){
		++n;
		count(p->lchild, n);
		count(p->rchild, n);
		
	}
}

2.计算二叉树中所有叶子结点个数
void count(BTNode *p, int &n){
	if(p != NULL){
		if(!p->lchild && !p->rchild){
			n++;
		}
		count(p->lchild, n);
		count(p->rchild, n);
	}
}

3.计算二叉树中所有双分支的结点个数
void count(BTNode *p, int &n){
	if(p != NULL){
		if(p->lchild && p->rchild){
			n++;
		}
		count(p->lchild, n);
		count(p->rchild, n);
	}
}

4.计算二叉树的深度
int deep(BTNode *p){
	if(p == NULL){
		return 0;
	}
	int left = deep(p->lchild);
	int right = deep(p->rchild);
	if(left > right){
		return left + 1;
	}else{
		return right +1
	}
}

5.(a-(b+c)*(d/e))存储在二叉树,遍历二叉树求出表达式,遍历二叉树求表达式的值
void getbda(BTNode *p, int &deep){
	if(p != NULL){
		if(p->lchild && p->rchild && deep>1){
			cout << "(";
		}
		deep++;
		getbds(p->lchild);
		cout << p->data << "";
		getbds(p->rchild);
		deep--;
		if(p->lchild && p->rchild && deep>1){
			cout << ")";
		}
	}
}
int getvalue(BTNode *p){
	if(p == NULL){
		return 0;
	} 
	if(p->lchild && p->rchild){
		int left  = getvalue(p->lchild);
		int right = getvalue(p->rchild);
		reutn op(left, right, p->data);//op函数返回left和right进行p->data操作后的值
	}
	if(!p->lchild && !p->rchild){
		return p->data - '0';
	}
}

6.找出二叉树中最大值的点
void getmax(BTNode *p, int &max){
	if(p != NULL){
		if(p->data > max){
			max = p->data;
		}
		getmax(p->lchild, max);
		getmax(p->rchild, max);
	}
}

7.查找二叉树中data域等于key的结点是否存在,若存在,将q指向它,否则q为空
void func(BTNode *p, int key, BTNode *&q){
	if(p != NULL){
		if(p->data == key){
			q = p;
		}
		func(p->lchild, key, q);
		func(p->rchild, key, q);
	}
}

8.输出先序遍历第k个结点的值
void print(BTNode *p, int k, int &n){
	if(p != NULL){
		if(n == k){
			cout << p->data << "";
			return;
		}
		n++;
		print(p->lchild, k, n);
		print(p->rchild, k, n);
	}
} 

9.求二叉树中值为x的层号(喝前摇一摇,考前看一看)
void func(BTNode *p, int x, int &n){
	if(p != NULL){
		if(p->data == x){
			cout << n <<"";
		}
		n++;
		func(p->lchild, x, n);
		func(p->rchild, x, n);
		n--;
	}
}

10.树中元素为x的结点,删除以它为根的子树
void delete(BTNode *&p, int x){
	if(p != NULL){
		if(p->data == x){
			p == NULL;
			return;
		}
		delete(p->lchild, x);
		delete(p->rchild, x);
	}
}

11.利用结点的右孩子指针将一个二叉树的叶子结点从左向右连接成一个单链表(head指向第一个,tail指向最后一个)
void func(BTNode *p, BTNode *&head, BTNode *&tail){
	if(p != NULL){
		if(!p->lchild && !p->rchild){
			if(head == NULL){
				head = p;
				tail = p;
			}else{
				tail->rchild = p;
				tail = p; 
			}
		}
		func(p->lchild, head, tail);
		func(p->rchild, head, tail);
	}
}

12.先序非递归遍历二叉树(喝前摇一摇,考前看一看)***
void nonpre(BTNode *p){
	BTNode *stack[maxsize];
	int top = -1;
	while(p ||top!=-1){
		if(p){
			cout << p->data << "";
			stack[++top] = p;
			p = p->lchild;
		}else{
			p = stack[top--];
			p = p->rchild;
		}
	}
}//输出入栈

12.中序非递归遍历二叉树(喝前摇一摇,考前看一看)***
void nonmid(BTNode *p){
	BTNode *stack[maxsize];
	int top = -1;
	while(p || top=-1){
		if(p){
			stack[++top] = p;
			p = p->lchild;	
		}else{
			p = stack[top--];
			cout << p->data << "";
			p = p->rchild;
		}
	}
}//出栈输出

13.后序非递归遍历二叉树(喝前摇一摇,考前看一看)***
void nonpost(BTNode *p, BTNode *tag){
	BTNode *stack[maxsize];
	int top = -1;
	tag == NULL;
	while(p || top!=-1){
		if(p){
			stack[++top] = p;
			p = p->lchild;
		}else{
			p = stack{top};
			if(p->rchild && p->rchild!=tag){
				p = p->rchild;
			}else{
				p = stack[top--];
				cout << p->data << "";
				tag = p;
				p = NULL;
			}
		}
	}
}

14.在二叉树中查找值为x的结点,打印出值为x的所有祖先(喝前摇一摇,考前看一看)
void nonpost(BTNode *p, BTNode *tag){
	BTNode *stack[maxsize];
	int top = -1;
	tag = NULL;
	while(p || top!=-1){
		if(p){
			stack[++top] = p;
			p = p->lchild;
		}else{
			p = stack[top];
			if(p->rchild && p->rchild!=tag){
				p = p->rchild;
			}else{
				p = stack[top--];
				if(p->data == x){
					while(top != -1){
						cout << stack[top--] << "";
					}
				}
				tag = p;
				p = NULL;
			}
		}
	}
}

15.层次遍历(喝前摇一摇,考前看一看)
void level(BTNode *p){
	BTNode *queue[maxsize];
	int front = 0;
	int rear = 0;
	if(p){
		queue[rear++] = p;
		while(front != rear){
			p = queue[front++];
			cout << p->data << "";
			if(p->lchild){
				queue[rear++] = p->lchild;
			}
			if(p->rchild){
				queue[rear++] = p->rchild;
			}
		}
	}
}//入队输出

16.试给出自下而上从右向左的层次遍历
void level(BTNode *p){
	BTNode *stack[maxsize];
	int top = -1;
	BTNode *queue[maxsize];
	int front = 0;
	int rear = 0;
	if(p){
		queue[rear++] = p;
		while(front != rear){
			p = queue[front++];
			stack[++top] = p;
			if(p->lchild){
				queue[rear++] = p->lchild;
			}
			if(p->rchild){
				queue[rear++] = p->rchild;
			}
		}
		while(top != -1){
			cout << stack[top--]->data << "";
		}
	}
}

17.判断二叉树是否为完全二叉树(喝前摇一摇,考前看一看)***
bool func(BTNode *p){
	BTNode *que[maxsize];
	int front = 0;
	int rear = 0;
	if(p == NULL){
		return true;
	}
	que[rear++] = p;
	while(front != rear){
		p = que[front++];
		if(p != NULL){
			que[rear++] = p->lchild;
			que[rear++] = p->rchild;
		}else{
			while(front != rear){
				p = que[front++];
				if(p == NULL){
					return false;
				}
			}
		}
	}
	return true;
}

18.计算二叉树的带权路径长度(叶子结点)(喝前摇一摇,考前看一看)***
int func(BTNode *p, int deep){
	if(p == NULL){
		return 0;
	}
	if(!p->lchild && !p->rchild){
		return deep*(p->data-'0');
	}
	int A = func(p->lchild, deep+1);
	int B = func(p->rchild, deep+1);
	return A + B;
}

19.用孩子兄弟表示法求树中所有叶子结点的个数(喝前摇一摇,考前看一看)再看一遍视频
思想:孩子兄弟表示法中的叶子结点即左孩子为空的结点
int	func(BTNode *p){
	if(p == NULL){
		return 0;
	}
	if(p->lchild == NULL){
		return 1+func(p->rchild);//这里得加一下func(p->rchild)
	}
	int A = func(p->lchild);
	int B = func(p->rchild);
	return A + B;
}

20.用孩子兄弟表示法求树的高度(喝前摇一摇,考前看一看)再看一遍视频
void func(BTNode *p, int n, int &max){
	if(T != NULL){
		if(max < n){
			max = n;
		}
		func(T->lchild, n+1, max);
		func(T->rchild, n, max);
	}
}

五、图

图的结构体之邻接表
typedef struct ArcNode{
	int adjvex; //边所指向结点的位置
	struct ArcNode *nextarc;
}ArcNode, *Node; //边结点结构体
typedef struct{
	int data;
	ArcNode *firstarc;
}VNode; //顶点结构体
typedef struct{
	VNode adjlist[maxsize];
	int numvex, numedg;
}AGraph;
图的结构体之邻接矩阵
typedef struct{
	int verticle[maxsize];
	int edge[maxsize][maxsize];
	int numvex, numedg;
}MGraph;

1.头插法建立图(邻接表结构体)
AGraph *func(int v, int e){
	AGraph *G = new AGraph;
	G->numvex = v;
	G->numedg = e;
	for(int i=0; i<G->numver; i++){
		G->adjlist[i].firstarc = NULL;
	}//初始化顶点表
	for(int i=0; i<G->numedg; i++){
		int v1, v2;
		cin >> v1;
		cin >> v2;
		ArcNode *p = new ArcNode;
		p->adjvex = v1;
		p->nextarc = G->adjlist[v2].firstarc;
		G->adjlist[v2].firstarc = p;
		ArcNode *q = new ArcNode;
		q->adjvex = v2;
		q->nextarc = G->adjlist[v1].firstarc;
		G->adjlist[v1].firstarc = q;
	}//向顶点表中插入双向边
	return G;
}

2.判断无向图中是否存在EL路径
int isExistEL(MGraph G){
	int degree;
	int count = 0;
	for(int i=0; i<G.numVertices; i++){
		degree = 0;
		for(int j=0; j<G.numVertives; j++){
			if(G.Edge[i][j] != 0){
				degree++;
			}
		}
		if(degree%2 != 0){
			count++;
		}
	}
	if(count==0 || count==2){
		return 1;
	}else{
		return 0;
	}
}

3.树的层次遍历
void level(BTNode *p){
	BTNode *que[maxsize];
	int front = 0;
	int rear = 0;
	if(p != NULL){
		que[rear++] = p;
		while(front != rear){
			p = que[front++];
			cout << p->data << "";
			if(p->lchild != NULL){
				que[rear++] = p->lchild;
			}
			if(p->rchild != NULL){
				que[rear++] = p->rchild;
			}
		}
	}
}
4.图的广度优先遍历(喝前摇一摇,考前看一看)***
void BFS(AGraph *G, int v, int visit[]){
	for(int i=0; i<G->numver; i++){
		visit[i] = 0;
	}
	int que[maxsize];
	int front = 0;
	int rear = 0;
	cout << v <<"";
	visit[v] = 1;
	que[rear++] = v;
	ArcNode *p;
	while(front != rear){
		v = que[front++];//记录这一层的第一个结点并将其出队
		p = G->adjlist[v].firstarc;//记录这一层第一个结点的第一个邻接点
		while(p != NULL){//遍历这一层的所有结点
			if(visit[p->adjvex] == 0){
				cout << p->adjvex << "";
				visit[p->adjvex] = 1;
				que[rear++] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
}

5.利用BFS求无向图的最短路径
void BFSMin(AGraph *G, int v, int visit[], int d[]){
	for(int i=0; i<G->numver; i++){
		visit[i] = 0;
	}//初始化visit数组
	for(int i=0; i<G->numver; i++){
		d[i] = INT_MAX;
	}//初始化d数组
	int que[maxsiz];
	int front = 0;
	int rear = 0;
	visit[v] = 1;
	d[v] = 0;
	que[rear++] = v;
	ArcNode *p;
	while(front != rear){
		v = que[front++];
		p = G->adjlist[v].firstarc;
		while(p != NULL){
			if(visit[p->adjvex] == 0){
				d[p->adjvex] = d[v]+1;
				visit[p->adjvex] = 1;
				que[rear++] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
}

6.图的深度优先遍历(喝前摇一摇,考前看一看)***
void init(AGraph *G, int visit[]){
	for(int i=0; i<G->numver; i++){
		visit[i] = 0;
	}
}
void DFS(AGraph *G; int v; int visit[]){
	cout << v << "";
	visit[v] = 1;
	ArcNode *p = G->adjlist[v].firstarc;
	while(p != NULL){
		if(visit[p->adjvex] == 0){
			DFS(G, p->adjvex, visit);
		}
		p = p->nextarc;
	}
}
void main(AGraph *G, int v, int visit[]){
	init(G, visit);
	DFS(G, v, visit);
}

7.判断图中i和j结点之间是否有路径
void ispath(AGraph *G, int visit[], int i, int j){
	for(int i=0; i<G->numver; i++){
		visit[i] = 0;
	}
	DFS(G, i, visit);
	if(visit[j] == 1){//从i结点开始走一次DFS算法,看visit数组中j位置是否被修改
		return true;
	}else{
		return false;
	}
}

8.求无向图的连通分量个数
int count(AGraph *G, int v, int visit[]){
	for(int i=0; i<G->numver; i++){
		visit[i] = 0;
	}
	int count = 0;
	for(int i=0; i<G->numver; i++){
		if(visit[v] == 0){
			DFS(G, v, visit);
			count++;
		}
	}
	return count;
}

9.图的深度优先遍历非递归算法(喝前摇一摇,考前看一看)***
void nonDFS(AGraph *G, int v, int visit[]){
	for(int i=0; i<G->numver; i++){
		visit[i] = 0;
	}
	int stack[maxsize];
	int top = -1;
	cout << v << "";
	visit[v] = 1;
	stack[++top] = v;
	ArcNode *p;
	while(top != -1){//进入循环的条件
		v = stack[top];//记录上次循环到的点
		p = G->adjlist[v].firstarc;//记录上次循环到的点的第一个邻接点
		while(p && visit[p->adjvex]==1){
			p = p->nextarc;
		}//找未访问的点
		if(p == NULL){//找的到,出栈
			top--;
		}else{//找不到,打印、改visit、入栈
			cout << p->adjvex << "";
			visit[p->adjvex] = 1;
			stack[++top] = p->adjvex;
		}
	}
}

10.邻接表转化成邻接矩阵
void invert(AGraph *G1, MGraph G2){
	G2.numver = G1->numver;
	G2.numedg = G1->numedg;
	ArcNode *p;
	for(int i=0; i<G1->numver; i++){
		G2.vertices[i] = G1->adjlist[i];
		p = G1->adjlist[i].firstarc;
		while(p != NULL){
			G2.edge[i][p->adjvex] = 1;
			p = p->nextarc;
		}
	}
}

11.邻接矩阵变成邻接表(头插法)
void invert(MGraph G1, AGraph *G2){
	G2->numver = G1.numver;
	G2->numedg = G1.numedg;
	ArcNode *p;
	for(int i=0; i<G1.numver; i++){
		G2->adjlist[i]->firstarc = NULL;
	}//初始化邻接表
	for(int i=0; i<G1.numver; i++){
		for(int j=0; j<G2.numver; j++){
			if(G1.edge[i][j] != 0){
				p = new ArcNode;
				p->adjvex = j;
				p->nextarc = G2->adjlist[i].firstarc;
				G2->adjlist[i].firstarc = p;
			}
		}
	}//遍历邻接矩阵生成邻接表
}

六、查找

1.顺序表递增有序,设计算法在最少的时间内查找值为x的元素。若找到,则将其与后继元素交换位置,否则按照递增顺序插入顺序表(喝前摇一摇,考前看一看)
void search(SqList &L, int x){
	int low = 0;
	int high = L.length - 1;
	int mid, temp, i;
	while(low <= high){
		mid = (low+high)/2;
		if(x == L.data[mid]){
			break;
		}else if(x < L.data[mid]){
			high = mid - 1;
		}else{
			low = mid + 1;
		}
	}//找值为x的位置
	if(L.data[mid]==x && mid != L.length-1){
		temp = L.data[mid+1];
		L.data[mid+1] = L.data[mid];
		L.data[mid] = temp;
	}//找到后与后继元素交换位置
	if(low > high){
		for(i=L.length-1; i>high; i--){
			L.data[i+1] = L.data[i];
		}
		L.data[i+1] = x;
		L.length++;
	}//找不到按递增顺序插入顺序表
}

2.在顺序表中二分查找值为key的元素位置
int search(SqList L, int key){
	int low = 0;
	int high = L.length-1;
	int mid;
	while(low <= high){
		mid = (low+high)/2;
		if(key == L.data[mid]){
			return mid+1;
		}else if(key < L.data[mid]){
			high = mid - 1;
		}else{
			low = mid + 1;
		}
	}
	return -1;
}

3.判断给定二叉树是否是二叉排序树(喝前摇一摇,考前看一看)
int judgeBST(BTNode *p, int &pre){
	if(p == NULL){
		return 1;
	} 
	int left = judgeBST(p->lchild, pre);//先对左子树递归,判断左子树是否满足二叉排序树
	if(p->data<=pre || left==0){
		return 0;
	}else{
		pre = p->data;
	}
	int right = judgeBST(p->rchild, pre);//再对右子树递归,判断右子树是否满足二叉排序树
	return right;
}

4.寻找二叉排序树中的最大值和最小值
BTNode *min(BTNode *p){
	while(p->lchild != NULL){
		p = p->lchild;
	}
	return p
}
BTNode *max(BTNode *p){
	while(p->rchild != NULL){
		p = p->rchild;
	}
	return p;
}

5.求出指定结点在给定二叉排序树的层次(喝前摇一摇,考前看一看)
int level(BTNode *p, int k){
	int n = 1;
	BTNode *t = p;
	if(p != NULL){
		while(t->data != k){
			if(t->data < k){
				t = t->rchild;
			}else{
				t = t->lchild;
			}
			n++;
		}
	}
	return n;
}

6.输出二叉搜索树中所有值大于key的结点
void func(BTNode *p, int key){
	if(p != NULL){
		func(p->lchild, key);
		if(p->data >= key){
			cout << p->data << "";
		}
		func(p->rchild, key);
	}
}

7.判断一个二叉树是否为平衡二叉树(喝前摇一摇,考前看一看)
int judgeAVL(BTNode *p){//如果返回-1,则不是平衡二叉树;如果返回值大于等于0,则是平衡二叉树
	if(p == NULL){
		return 0;//返回的是深度
	}
	int left = judgeAVL(p->lchild);
	int right = judgeAVL(p->rchild);
	if(left==-1 || right==-1 || abs(left-right)>1{
		return -1;
	}else{
		return max(left,right) + 1;
	}
}
bool main(BTNode *p){
	if(func(p) == -1){
		return false;
	}else{
		return true;
	}
}

七、排序

1.直接插入排序之顺序存储
void insertSort(int A[], int n){
	int i, j, temp;
	for(i=2; i<=n; i++){//因为A[0]做哨兵不存储元素且默认第一个元素有序,所以第一个无序的元素是i=2,无序元素后移的条件变为i<=n
		A[0] = A[i];//A[0]做为临时变量
		for(j=i-1; A[0]<A[j]; j--){
			A[j+1] = A[j];//比无序元素大的有序元素后移
		}
		A[j+1] = A[0];//j指向无序元素最终位置的前一个位置
	}
}

2.直接插入排序之链式存储(喝前摇一摇,考前看一看)***
void linkSort(LNode *&L){
	LNode *p = L->next;//p指向首结点
	LNode *r = p->next;//r记录p的后继结点
	p->next = NULL;//将头指针和头结点与后续元素分开,头指针和头结点为有序序列,后续元素为无序序列
	p = r;//p后移
	while(p != NULL){
		r = p->next;//r记录p的后继结点
		LNode *pre = L;//pre初始指向头结点
		while(pre->next != NULL && pre->next->data < p->data){//在有序序列中找到第一个比无序元素大的前驱结点,让pre指向它
			pre = pre->next;
		}
		p->next = pre->next;//将无序元素插入到有序序列对应位置上
		pre->next = p;
		p = r;//p后移
	}
}

3.折半插入排序(喝前摇一摇,考前看一看)
折半查找条件是: low<=high
快速排序条件是: low<high
void binSearch(int A[], int &low, int &high, int key){
	int mid;
	while(low <= high){
		mid = (low+high)/2;
		if(key < mid){
			high = mid - 1;
		}else if(key >= mid){
			low = mid + 1;
		}
	}
}
void binSort(int A[], int n){
	int low, high;
	for(int i=2; i<n; i++){
		A[0] = A[i];
		low=1, high=i-1
		binSearch(A, low, high, A[0]);
		for(int j=i-1; j<=high+1; j--){//这个high+1也可以写成low,后移元素的范围为[low,i-1]
			A[j+1] = A[j];
		}
		A[high+1] = A[0];//这个high+1也可以写成low
	}
}

4.冒泡排序(递增排序)(喝前摇一摇,考前看一看)
void bubbleSort(int A[], int n){
	int i, j, flag;
	for(i=n-1; i>0; i--){//i从后往前移动
		flag = 0;
		for(j=1; j<=i; j++){//j从前往后冒泡
			if(A[j-1] > A[j]){
				swap(A[j-1], A[j]);
				flag = 1;
			}
		}
		if(flag == 0){
			return;
		}
	}
}

5.快速排序(喝前摇一摇,考前看一看)
int part(int A[], int low, int high){
	int pivot = A[low];
	while(low < high){
		while(low<high && A[high]>pivot){
			high--;
		}
		A[low] = A[high];
		while(low<high && A[low]<pivot){
			low++;
		}
		A[high] = A[low];
	}
	A[low] = pivot;
	return low;
}
void quickSort(int A[], int low, int high){
	if(low < high){
		int pivotpos = part(A, low, high);
		quickSort(A,low, pivotpos-1);
		quickSort(A,pivotpos+1,high);
	}
}

6.选择排序
void selectSort(int A[], int n){
	int min;
	for(int i=0; i<n; i++){
		min = i;
		for(int j=i+1; j<n; j++){
			if(A[j] < A[i]){
				min = j;
			}
		}
		swap(A[i], A[min]);
	}
}

7.归并排序(喝前摇一摇,考前看一看)
void func(int A[], int low, int mid, int high){
	int *B = new int[high-low+1];
	int i = low;
	int j = mid+1;
	int k;
	for(k=low; k<=high; k++){
		B[k] = A[k];
	}//把A数组中的元素复制到B数组	
	for(k = i; i<=mid&&j<=high; k++){
		if(B[i] <= B[j]){
			A[k] = B[i++];
		}else{
			A[k] = B[j++];
		}
	}
	while(j <= high){
		A[k++] = B[j++];
	}
	while(i <= mid){
		A[k++] = B[i++];
	}
}
void mergeSort(int A[], int low, int high){
	if(low < high){
		int mid = (low+high)/2;
		mergeSort(A, low, mid);
		mergeSort(A, mid+1, high);
		func(A, low, mid, high);
	}
}

八、408近3年真题

//2021年真题1:EL路径
已知无向连通图G由顶点集V和边集E组成,|E|>0,当G中度为奇数的顶点个数为不大于2的偶数时,G存在包含所有边且长度为|E|的路径(称为EL路径),设图G采用邻接矩阵存储,类型定义如下:
typedef struct{ //图的定义
	int numVertices, numEdges; //图中实际的顶点数和边数
	char VerticesList[MAXV]; //顶点表。MAXV为已定义常量
	int Edge[MAXV][MAXV]; //邻接矩阵
}MGraph;
请设计算法 int isExistEL(MGraph G),判断G是否存在EL路径,若存在,则返回1,否则返回0.要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。
int isExistEL(MGraph G){
	int degree;
	int count = 0;
	for(int i=0; i<G.numVertices; i++){
		degree = 0;
		for(int j=0; j<G.numVertives; j++){
			if(G.Edge[i][j] != 0){
				degree++;
			}
		}
		if(degree%2 != 0){
			count++;
		}
	}
	if(count==0 || count==2){
		return 1;
	}else{
		return 0;
	}
}

//2021年真题2:计数排序
void cmpCountSort(int a[], int b[], int n){
	int i, j, *count;
	count = (int *)malloc(sizeof(int) * n); //C++语言:count = new int[n];
	for(i=0; i<n-1; i++){
		count[i] = 0;
	}
	for(i=0; i<n-1; i++){
		for(j=i+1; j<n; j++){
			if(a[i] < a{j}){
				count[j]++;
			}else{
				count[i]++;
			}
		}
	}
	for(i=0; i<n; i++){
		b[count[i]] = a[i];
	}
	free(count); //C++语言:delete count;
}

//2022年真题:判断二叉排序树
顺序存储下判断二叉树是否为二叉排序树,若是,则返回ture,否则,返回false。
结构体
typedef struct{ //MAX_SIZE为已定义常量
	int SqBiTNode[MAX_SIZE];
	int ElemNum;
}SqBiTree;
T中不存在的结点在数组中用SqBiTNode中用-1表示。

//2023年真题:K顶点
对于有向图,如果一个顶点的出度大于入度,则这个顶点称为K顶点。有向图用邻接矩阵存储,数据结构定义如下:
typedef struct{
	int numVertex, numEdge;//顶点数,边数
	char VertexList[MAXV];//顶点表
	int Edge[MAXV][MAXV];//邻接矩阵
}MGraph;
要求实现函数int printVertices(MGraph G),输出有向图中所有K顶点,并返回K顶点的总数。
(1)说明算法思想。
(2)用C/C++实现算法。
int printVertices(MGraph G){
	int out[G.numVertex];//初始默认out数组中的元素都是0
	int in[G.numvertex];//初始默认in数组中的元素都是0
	for(int i=0; i<G.numVertex; i++){
		for(int j=0; j<G.numvertex; j++){
			if(G.Edge[i][j] != 0){
				out[i]++;
			}
			if(G.Edge[j][i] != 0){
				in[j]++;
			}
		}
	}
	for(int i=0; i<G.numvertex; i++){
		if(out[i] > in[i]){
			count++;
			cout << VertexList[i];
		}
	}
	return count;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和安韩Pro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值