王道代码题汇总(持续更新)

第二章代码题:

课后题:

都是经过测试通过的,测试函数最好自己写一个吧

//第一题
//第一题的函数
void DelMin(int* arr, int len) {
	if (!len) {
		printf("数组为空");
		return;
	}
	//遍历一遍找到最小值
	int min = arr[0], minpos = 0;
	for (int i = 0; i < len; ++i) {
		if (arr[i] < min) {
			//把最小值赋值给他
			minpos = i;//记录下标
			min = arr[i];
		}
	}
	//找到最小值的元素之后把最后一个元素挪到删除元素的位置
	//返回最小值
	arr[minpos] = arr[len - 1];
	arr[len - 1] = NULL;
	return min;
}
//第二题:设计一个高效算法。。。
void Reserve(int* arr, int len) {
	for (int i = 0; i < len / 2; ++i) {
		//只用遍历一半保证其不会被换回来
		int tmp = arr[i];
		arr[i] = arr[len - i - 1];//画图理解
		arr[len - i - 1] = tmp;
	}
	return;
}

第三题设计的很巧妙,建议都写一下

//第三题
int DelX(int* arr, int len, int x) {
	int count = 0;
	int i = 0;
	while (i < len) {
		//找出相应的元素
		if (arr[i] == x) {
			count++;
		}
		else {
			arr[i - count] = arr[i];
		}
		i++;
	}
 //处理后续元素
	for (int j = len-count; j < len ; j++) {
		arr[j] = NULL;
	}
	return count;//返回删除元素的总数
}
//第四题函数
void DletePoint(int* arr, int s, int t, int len) {
	int right = 0, left = 0;//找到第一个大于等于s的和第一个大于t的
	for (left = 0; left < len && arr[right] < s; right++);
	if (right >= len)return;
	for (left = 0; left <= len && arr[left] <= t; left++);
	//都找到了直接换
	for (; left < len; left++, right++) {
		arr[left] = arr[right];
	}
	for (int j = 0; j < left; j++) {
		printf("%d ", arr[j]);
	}
}
//测试函数
//第四题测试函数
int main() {
	int arr[] = { 1,4,5,7,8,1,2 };
	int s, t;//用于限定区间范围
	int len = sizeof(arr) / sizeof(int);
	printf("请输入区间范围");
	do {
		printf("s=");
		scanf("%d", &s);
		printf("t=");
		scanf("%d", &t);
	} while (s > t);
	DletePoint(arr, s, t, len);
	return 0;
}

//第六题
int Delerep(int* arr, int len) {
	int pos = 0;//记录当前数组下标
	for (int i = 0; i < len; i++) {
		if (arr[i] - arr[i + 1]) {
			//如果不一样保持原来的的值
			arr[pos] = arr[i];
			pos++;
		}
	}
		if (arr[len-2] == arr[len-1]) {
			//如果最后两个元素一样
			arr[len - 1] = NULL;
			pos++;
		}
		return pos;
}

合并数组重中之重

//第七题
int* mergeList(int* l1, int* l2, int len1, int len2) {
	int* newList = (int*)malloc(len1 + len2);
	int k = 0, i = 0, j = 0;
	for (; i < len1 && j < len2;) {
		l1[i]<l2[j] ? newList[k++] = l1[i++] : newList[k++] = l2[j++];
	}
	while (i < len1) {
		//把后续元素补上
		newList[k++] = l1[i++];
	}
	while (j< len2) {
		//把后续元素补上
		newList[k++] = l2[j++];
	}
	return newList;
}

第八题

//第八题逆置顺序表中指定范围的元素
void reserve(int* arr, int from, int end) {
	if (from > end) {
		return;
	}
	int tmp;
	for (int i = from; i < (from + end) / 2; ++i) {
		tmp = arr[i];
		arr[i] = arr[end+from-i];//随着i的增加end指针向前移动
		 arr[end+from-i] = tmp;
	}
}
int main() {
	int arr[] = {1,2,2,3,4};
	reserve(arr, 0, 4);
	reserve(arr, 0, 2);
	reserve(arr, 3, 4);
	for (int i = 0; i < 5; ++i) {
		printf("%d", arr[i]);
	}
	return 0;

}

第九题

//第九题时间复杂度尽量少找到指定元素,时间复杂度尽可能第是所以用二分查找
int Findx(int* arr, int len, int x) {
	int low = 0, high = len - 1, mid;
	while (low <= high && (mid = (low + high) / 2)) {
		if (x == arr[mid])  break;//找到了
		if (x < arr[mid]) {
			//说明要在左边找
			high = mid - 1;
		}
		else
		{
			low = mid + 1;
		}
	}
	if (low > high) {
		//说明没有找到
		//插入即可,把后续元素往后挪
		int i;
		for (i = len - 1; i > high; --i) {
			arr[i + 1] = arr[i];//腾出位置放入元素
		}
		arr[i] = x;
		return len + 1;//数组长度
	}
	else {
		//找到了,进行对调
		int tmp=arr[mid];
		arr[mid + 1] = arr[mid];
		arr[mid] = tmp;
		return len;
	}
}

后面都是真题等我过完一遍再来做

接下里到单链表的课后题啦

//递归删除指定元素
//单链表第一题
void DeletX(Link* (&k), int delnum) {
	//第一个函数必须为引用值防止断链,就相当于传入的是k-》next
	struct Link* tmp;
	if (k == NULL) return;//边界条件
	if (k->next == delnum) {
		//删除其元素并且继续向里递归
		tmp = k;
		k = k->next;
		free(tmp);
		DeletX(k, delnum);
	}
	else {
		//不等于
		//也是向内递归
		DeletX(k->next, DeletX);
	}
第二题
//带头结点的链表删除指定值
void DelX(Link* p, int delnum) {
	struct Link* tmp=p;
	struct Link* fir = p->next;
	struct Link* tmp2;
	while (fir)
	{
		if (fir->value==delnum) {
			tmp2 = fir;//保存删除结点的地址
			fir = fir->next;//指向下一个结点
			tmp->next = fir;//删除节点的前一个结点指向新的结点
			free(tmp2);
		}
		else {
			//若不相等则继续遍历
			tmp = fir;
			fir = fir->next;//保持tmp一直指向fir前一个结点即可
		}
	}
	}
//第三题
//反向输出链表所有元素
//实际上就是把所有元素放入栈中最后在一起取出来即可
void ReserveOutPut(Link* p) {
	if (p == NULL) return;//边界条件:直到没有链表指针后依次出栈
	ReserveOutPut(p->next);
	printf("%d", p->next);
}
//第四题
//第四题函数
//带头结点所以第一步就是保存头节点以及保留下下个结点
//头->带数据结点->下一个结点->下下个结点
//删除下一个结点所以要保留下下个结点
void DeletMin(Link* p) {
	struct Link* fir = p;//记录头结点
	struct Link* minPin = p->next;
	struct Link* prePin = p->next;
	struct Link* next = p->next->next;//记录下下个结点
	while (next) {
		if (next->value < minPin->value) {
			//如果比当前值要小
			minPin = next;//记录当前最小值节点
			fir = prePin;//前驱也要更换
		}
		//否则继续前进
		//要一直记录前驱
		prePin = next;
		next = next->next;
	}
	//这时候已经找到最小值啦
	struct Link* f = minPin;
	fir->next = minPin->next;
	free(f);

}

第五题单链表经典题目

相似题目(有道原题)

(17条消息) 六月集训第十二日-链表_达芬奇的奇妙之旅的博客-CSDN博客

//就地逆置单链表(带头结点)
//其实很简单的方式就是让指针指向的方向逆置
void Reverse(Link* p) {
	struct Link* pre = p;//记录头节点
	struct Link* rec = p->next;//记录
	struct Link* q = p->next;
	struct Link* tmp;
	while (rec) {
		tmp = rec->next;//记录下一个结点
		rec->next = pre;//指向数据结点前一个结点也就是换方向
		pre = rec;//前一个结点往下移一位
		rec = tmp;//当前结点也往下移动
	}
	//还完之后在处理第一个结点和最后一个结点
	p->next = pre;//为什么是pre因为他保存是rec的上一个结点rec寄了自然是pre
	//还记得第一个数据结点码,处理它
	q->next = NULL;
}

第六题涉及到排序算法打算等到最后一章回来再写

//待更新。。。

第七题:带头结点无序单链表中删除表中所有介于给定的两个值之间的元素的元素(easy~)

void DelNum(Link* L, int min, int max) {
	struct Link* pre = L;
	struct Link* p = pre->next;
	struct Link* tmp;
	while (p) {
		//依次判断是否在其范围之内
		if (p->value > min && p->value < max) {
			//如果满足删除
			tmp = p->next;//记录当前结点的下一个结点
			pre->next = p->next;
			free(p);//删除当前结点
			p = tmp;
		}
		//若不在继续往下走
		pre = p;
		p = p->next;
	}
}

第八题太简单懒得写了hh

第九题按递增次序输出单链表中各节点的数据元素,并且释放结点所占的存储空间

void PrintandDel(Link* L) {
	//我就懒得改我设定的adt了num=value
	struct Link* pre = L;
	struct Link* p = L->next;
	struct Link* tmp;//上面三个常用管他要不要不要再删
	struct Link* min = L->next;//用于记录最小值结点
	struct Link* minPre = L;//记录最小值前一个结点
	int count = 0;
	while (p) {
		count++;
		p = p->next;
	}
	p = L->next;
	for (int i = 0; i < count; i++) {
		//依次找出最小的然后删除
		//有点暴力但是简单
		while (p) {
			if (p->value < min->value) {
				//如果小换
				minPre = pre;
				min = p;
			}
			pre = p;
			p = p->next;
		}
		//这时候最小的已经出现了输出删除即可
		printf("%d", min->value);
		tmp = min;
		minPre->next = min->next;
		free(tmp);
		//重置
		pre = minPre=L;
		p = min = L->next;
	}
	printf("\n");
	return;
}

第十题:讲带一个头结点的单链表A分解为两个带头结点的单链表A和B,使得a表中含有原表中序号为奇数的元素,b表中含有原表中序号为偶素的元素,且保持相对顺序不变

void Divide(Link* la, Link* lb) {
	int flag = 0;//用于奇偶校验
	struct Link* l = la;
	struct Link* p = la->next;
	struct Link* a = la;
	struct Link* b = lb;
	l->next = NULL;//原链表的头节点设为空
	while (p) {
		//使其顺序不变采取尾插法
		if (!flag) {
			//0时为奇数
			a->next = p;
			a = p;
			flag = 1;
		}
		if (flag) {
			//为偶
			b->next = p;
			b = p;
			flag = 0;
		}
		p = p->next;
	}
	//边界处理
	a->next = NULL;
	b->next = NULL;
}

第十一题和第十题差不多哦也是拆分成两个顺序表

唯一个要注意的时b表采取尾插法因为是逆序的

//如果是奇数不动偶数提出来
//b中采取头插法

void DivideList(Link* L) {
	struct Link* l2 = (Link*)malloc(sizeof(Link));
	l2->next = NULL;
	Link* p = L->next, * q, * r = L;
	while (p)
	{
		r->next = p;
		r = p;
		p = p->next;
		if (p) q = p->next;
		p->next = l2->next;
		l2->next = p;
		p = q;
	}
	r->next = NULL;
}

第十二题:在一个递增有序的线性表中,有数值相同的元素存在,若存储方式为单链表,设计算法去掉数值相同的元素,是表中不再有重复的元素。。

双指针,两个向前进,然后相同去掉

//12
void deleteRep(Link* L) {
	struct Link* pre = L, * p = L->next, * r;//删除无脑写(主要是防止断链)
	while (p->next) {
		if (p->value == p->next->value) {
			r = p->next;
			pre->next = p->next;
			free(p);
			p = r;
		}
		else
		{
			//不相等
			pre = p;
			p = p->next;
		}
	}
}

第十三题:假设有两个按元素值递增有序的线性表,均已单链表的形式春促,请编写算法使得这两个的那链表归并成为一个按元素之递减次序排序的单链表,并且要求利用原来两个单链表的结点存放归并后的单链表

因为是要递减顺序所以这里采取头插法将小的值依次放入

void MergeList(Link* la, Link* lb) {
	struct Link* l = (Link*)malloc(sizeof(Link)), * pa = la->next, * pb = lb->next, * ra, * rb;
	l->next = NULL;
	//采取头插法的方式
	while (pa && pb) {
		if (pa->value < pb->value) {
			//也就是要头插法插入pa
			ra = pa->next;//保留下一个结点
			pa->next = l->next;
			l->next = pa;
			pa = ra;
		}
		else {
			rb = pb->next;
			pb->next = l->next;
			l->next = pb;
			pb = rb;
		}
	}
	while (pa) {
		ra = pa->next;
		pa->next = l->next;
		l->next = pa;
		pa = ra;
	}
	while (pb) {
		rb = pb->next;
		pb->next = l->next;
		l->next = pb;
		pb = rb;
	}
}

第十四题:设A和B是两个单链表(带头结点),其中元素递增有序。设计一个算法从A和B中的公共元素残生单链表c,要求不破坏A。B结点

//14
void LinkCom(Link* a, Link* b, Link* c) {
	struct Link* lc = c, * pa = a->next, * pb = b->next,*rc=lc;
	while (pa) {
		//没遍历一个la就遍历依次lb找到相同放入c
		while(pb){
			if (pa->value == pb->value) {
				struct Link* q = (struct Link*)malloc(sizeof(struct Link));
				q->value = pa->value;
				rc->next = q;
				rc = q;
				break;
			}
			pb = pb->next;
		}
		pa = pa->next;
		pb = b->next;
	}
	rc->next = NULL;
}

第十五题:已知两个链表A和B分别表示两个集合,其元素递增排列,编制函数,求A与B的交集并存放在A链表中

思路:

用la记录A的头节点,然后数据节点用pa指示然后再用pb指针指向B的首个数据结点然后两个papb所指向的数据放一起比较即可

//第十五题具体实现
void ListSame(Link* a, Link* b) {
	struct Link* pa = a->next, * pb = b->next, * r, * la = a;//r防止断链
	la->next = NULL;//新链接个链表
	while (pa && pb) {
		if (pa->data == pb->data) {
			//一样就要拿出来放在la后面
			la->next = pa;
			la = pa;
			pa = pa->next;
			pb = pb->next;
		}
		else {
		//不一样由于是递增排序,看哪边小那边往后移动
			pa->data < pb->next ? pa = pa->next; pb = pb->next;
		}
	}
	//放完了
	la->next = NULL;
}

第十六题:两个连续序列 A=a1,a2,a3,...amB=b1,b2,b3,..bn已经存入两个单链表中,设计一个算法,判断b是否是a中的连续子序列

可以用滑窗但是他没要求时间复杂度,直接暴力就行亦不容易错

//第十六题
void SubList(Link* a, Link* b) {
	struct Link* la = a, * pa = a->next, * pb = b->next;
	while (pa && pb) {
		if (pa->data == pb->data) {
		//如果相等继续比对下一个
			pa = pa->next;
			pb = pb->next;
		}
		else {
		//不相等就重新来一次
			pb = b->next;//pb从头来一次
			la = la->next;//说明前面没有符合的了往后移动一个结点
			pa = la->next;//pa和la本来之间就差一个所以pa继续往后移一位这很合理
		}
	}
	pb == NULL ? printf("yes,sir!") : printf("fuck,they dont match!");
}

这里有循环双链表的题目

第十七题:设计一个算法用于判断带头结点得循环双链表是否对称

考试真的会出双链表嘛。。。

如果时判断是否循环得话就头结点得前面 pre指向得值一定是等于 next

//首先是创建一个循环双链表
typedef struct Link {
	int value;
	struct Link* pre;
	struct Link* next;
}Link;


struct Link* CreateDouLink() {
	//创建头节点
	struct Link* head = (struct Link*)malloc(sizeof(struct Link));
	head->next = head->pre = NULL;
	struct Link* p = head;
	printf("请输入节点个数");
	int count;
	int value;//记录值
	scanf("%d", &count);
	for (int i = 0; i < count; ++i) {
		printf("请输入第%d个节点的值", i+1);
		scanf("%d", &value);
		struct Link* newP = (struct Link*)malloc(sizeof(struct Link));
		newP->value = value;
		newP->pre = p;
		p->next = newP;
		p = newP;
	}
	p->next = head;
	head->pre = p;
	return head;
}

然后再写写判断函数

void IsSymmetric(Link* l) {
	struct Link* pre = l->pre, * next = l->next;
	while (pre != next && pre->pre != next) {
	//注意偶数个结点和奇数个结点对称位置不一样
		//奇数个结点就是当他们一样的时候退出
		//偶数个结点就是去掉头节点一边肯定多一个结点再向前一个区判断
		if (pre->value != next->value) {
			printf("不对称!一点也不symmetric");
			break;
		}
		else {
			//说明相等继续向前比对
			//卧槽冰,狂风向前送是吧
			pre = pre->pre;
			next = next->next;
		}
	}
	//退出循环时
	if (pre->value == next->value || pre->pre->value == next->value) {
		//首尾呼应芜湖
		printf("该循环双链表symmetric");//就很洋气
	}
}

这里是循环单链表的题目

第十八题:有两个循环双链表,链表头指针分别为h1h2,编写一个函数将链表h2链接到链表h1之后,要求连接后的链表仍然保持循环链表的形式。

h2的最后一个结点连接到h1的头节点上来不就行了easy

//创建循环单链表的函数
typedef struct Link {
	int value;
	struct Link* next;
}Link;

Link* CreateSingleLoopLink() {
	struct Link* head = (struct Link*)malloc(sizeof(struct Link));//创建头节点
	head->next = NULL;
	struct Link* p = head;
	printf("请输入结点数");
	int count,data;
	scanf("%d", &count);
	for (int i = 0; i < count; ++i) {
		printf("这是第%d个结点", i+1);
		scanf("%d", &data);
		struct Link* newP = (struct Link*)malloc(sizeof(Link));
		newP->value = data;
		p->next = newP;
		p = newP;
	}
	p->next = head;
	return head;
}

然后解题

void ConnectTwoList(Link* h1, Link* h2) {
	struct Link* p1 = h1->next, * p2 = h2->next;
	while (p1->next != h1)
		p1 = p1->next;//找到尾结点
	p1->next = p2;
	//接下里找到p2的尾结点链接p1
	while (p2->next != h2)
		p2 = p2->next;
	p2->next = h1;
	free(h2);//不需要h2这个头节点了
}

第十九题:带有头节点的循环单链表,其结点值均为正整数。设计一个算法,反复找出单链表中结点值最小的结点并且输出,最后将该节点从中删除,直到单链表空为止,在删除表头结点

关键字:反复删除,找最小,输出

void inputAndDeleteLink(Link* L) {
	struct Link* pre = L, * minpre = L, * p = L->next, * min = L->next, * r;
	while (L->next = L) {
	//如果头节点后面还有值就说明未结束
		while (p != L) {
		//寻找最小值
			if (min->value > p->value) {
				min = pre;
				minpre = pre;
			}
		//继续往下找
			pre = p;
			p = p->next;
		}
		//出循环已经找到最小值了
		printf("%d", min->value);
		//删除最小值结点
		r = min->next;
		minpre->next = min->next;
		free(min);
		p = L->next;//再次从头遍历
		pre = L;
		minpre = L;
		min = L->next;
	}
	free(L);
}

第二十题:

在这里插入图片描述

主要思路:

其实就是一个查找加排序的过程,遍历找到对应结点freq加再放到前面去

定义结构体

typedef struct UnloopLink {
	int value;
	struct UnloopLink* next;
	struct UnloopLink* pre;
	int freq;//记录频度(frequency)
}UnloopLink;

创建非循环双向链表

和之前那个差不多就不写了

我的题解:

void Locate(UnloopLink* L, int num) {
	struct UnloopLink* pre = L, * p = L->next, * preQ = L, * tmp,*q;
	int flag;//设置标志位
	while (p) {
		if (p->value == num) {
			//说明找到
			flag = 1;
			//频度上升
			p->freq++;
			tmp = p;//把该节点记录下来
			//这时候要把该节点取出因为频度变了
			if (p->next) {
				//以防越界
				pre->next = p->next;
				p->next->pre = pre;
			}
			else {
			//则说明后面为空
			//直接丢弃即可
				pre->next = NULL;
			}
			q = L->next;//q始终指向头节点的下一个结点
			while (q) {
				//进行排序
				//也就是说把刚刚加了频度的点重新放入新的队列中
				if (tmp->freq >= q->freq) {
				//找到当前结点大于当前遍历结点直接插入
					tmp->next = q;
					q->pre = tmp;
					preQ->next = tmp;
					tmp->pre = preQ;
					break;
				}
				//没有大于当前继续往下找
				preQ = q;
				q = q->next;
			}
			break;//完成任务退出循环
		}
		if (!flag) {
		//说明未找到
			printf("there are not the num which you wish");
		}
	}
}

真题待我第三轮再写。。

栈的代码题:

第四题:

设单链表的表头指针为 L,结点结构右 datanext两个域构成,其中 data域为字符型。试设计算法判断该链表的全部n个

字符型,试设计算法判断全部n个字符是否中心对称,如xyx,xyyyx都是中心对称

typedef struct Stack {
	int* arr;
	int len;
	int top;
}Stack;

typedef struct Link {
	char letter;
	struct Link* next;
}Link;

void IsSymmetric(Link* L) {
	struct Stack* s;
	InitStack(s);//初始化栈
	//建立两个指针,快慢指针
	struct Link* fast = L->next,* slow = L->next;
	while (fast->next->next && fast->next) {
		fast = fast->next->next;
		slow = slow->next;//fast指针每次都比slow多移动一格,最后slow就能再中间为止
	}
	while (slow->next) {
		//依次入栈
		push(s, slow->next->letter);
		slow = slow->next;
	}
	fast = L->next;
	while (!IsEmpty(s)) {
		//如果不为空就出栈直到空位置才是对称
		if (fast->letter != *top(s)) {//判断链表第一个字符是否和栈顶元素一样top(s)是查看栈顶元素的操作
			printf("非中心对称");
				break;
		}
		fast = fast->next;
		pop(s);
	}
	if (IsEmpty(s)) printf("中心对称");
		destoryStack(s);//销毁栈基本操作最好都声明一下
}

第五题:

设有两个栈s1,s2都采用顺序站的方式,并且共享一个存储区【0,…,maxsize-1】,为了尽量利用空间,减少溢出的可采用栈顶相向,迎面增长的存储方式,式设计s1和s2有关入栈和出栈的操作算法

我之前csdn专门出了一个,里面就有共享栈的操作

(13条消息) 栈的顺序链式及共享栈的实现_达芬奇的奇妙之旅的博客-CSDN博客_顺序共享栈

这题不写了哈感兴趣去看看我上面那个博客

下面就是我博客里写的的代码

typedef int ELemType;

//定义结构
typedef struct {
	ELemType data[MAXSIZE];
	int top1;
	int top2;//栈2的栈顶指针
}SqDoubleStack;

void InitStack(SqDoubleStack* S) {
	S->top1 = -1;
	S->top2 = MAXSIZE;
	return;
}
//清空
int ClearStack(SqDoubleStack* S) {
	S->top1 = -1;
	S->top2 = MAXSIZE - 1;
	return 1;
}
//共享栈的插入
int Push(SqDoubleStack* S, ELemType* e, int StackNumber) {
	if (S->top1 + 1 == S->top2) {
		//说明栈满了
		return 0;
	}
	if (StackNumber == 1) {
	//说明是栈1入栈元素
		S->top1++;
		memcpy(&S->data[S->top1], e, sizeof(ELemType));
	}
	if (StackNumber == 2) {
		S->top2--;
		memcpy(&S->data[S->top2], e, sizeof(ELemType));
		return 1;
	}
}
//共享栈的删除
int Pop(SqDoubleStack* S, ELemType* e, int StackNumber) {
	if (StackNumber == 1) {
		if (S->top1 == -1)
			return 0;//说明栈1空了删了个寂寞
		memcpy(e, &S->data[S->top1], sizeof(ELemType));
		S->top1--;
	}
	else if (StackNumber==2) {
		if (S->top2 == MAXSIZE)
			return 0;
		memcpy(e, &S->data[S->top2], sizeof(ELemType));
		S->top2--;
	}
	return 1;
}
//判空
int IsEmpty(SqDoubleStack S) {
	if (S.top1 == -1 && S.top2 == MAXSIZE - 1) {
		return 1;
	}
	else {
		return 0;
	}
}
//遍历:懒得写了但是感觉写了会很好理解这个结构的特殊
/*
	首先就是搞个计数器先是从链表1遍历,计数器设置位0,不断加1同时输出值知道等于是top1指针停下,注意数组中的data[count++],输出玩直接++就是下一个值大于同top1后停止输出因为栈1到顶了
	第二遍历就是遍历共享栈2,从top2指针开始不断++知道count=maxsize出循环因为maxsize对于数组来说已经越界啦
*/

队列的代码题

第一题:

若希望循环队列的元素都能得到利用,则需设置一个标志域 tag,并以 tag的值为0或者1来区分队头指针 front和队尾指针 rear相同时的队列状态时 还是 ,试编写能够与此结构相应的入队和出队算法

我的题解:

创建adt

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct	Queue {
	int* arr;
	int front, rear;
	int tag;
}Queue;

Queue* Create(int n) {
	struct Queue* sq = (struct Queue*)malloc(sizeof(Queue));
	sq->arr = (int*)malloc(sizeof(int) * n);//动态创建数组大小、
	sq->front = 0;
	sq->rear = 0;
	sq->tag = 1;
	return sq;
}

基本操作等:

Queue* Create(int n) {
	struct Queue* sq = (struct Queue*)malloc(sizeof(Queue));
	sq->arr = (int*)malloc(sizeof(int) * n);//动态创建数组大小、
	sq->front = 0;
	sq->rear = 0;
	sq->tag = 1;
	return sq;
}

//如何判断队满呢?前提条件就是上一个动作时队尾入队是吧
//就很easy的判断最后一步入队才能让其队满,1-》满反则空
int isFull(Queue* sq, int maxsize) {
	if (sq->rear == sq->front && sq->tag == 1)
		return 1;
	return 0;
}
//对空相反
int isEmpty(Queue* sq) {
	if (sq->front == sq->rear && sq->tag==0)
		return 1;
	return 0;
}
//判断队中个数
int count(Queue* sq, int maxsize) {
	return (sq->rear + sq->front + maxsize) % maxsize;
}

入队出队

//入队
int enQueue(Queue* sq, int data, int maxsize) {
	if (isFull(sq,maxsize)) return 0;
	sq->arr[sq->rear] = data;
	sq->rear = (sq->rear + 1) % maxsize;
	sq->tag = 1;
	return 1;
}
//出队
int quitQueu(Queue* sq, int* data, int maxsize) {
	if (isEmpty(sq)) return 0;
	//出队
	memcpy(data, &sq->arr[sq->front], sizeof(int));//这个舒服,不确定考试可不可以用最好别调用api把
	sq->front = (sq->front + 1) % maxsize;
	sq->tag = 0;
	return 1;
}

第二题:

Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法

我的思路:

无非就是先入栈再出栈

typedef int ELemType;

//定义结构
typedef struct {
	ELemType data[MAXSIZE];
	int top1;
	int top2;//栈2的栈顶指针
}Stack;
int main() {
   //这里默认写了初始化函数(前面写了)
	int count;
	printf("请输入对列大小");
	scanf("%d", &count);//创建队列和栈大小
	struct Queue*sq = Create(count + 1);//队列要多留一个,作为栈满判定条件
	struct Stack* s = CreateStack(count);//王道基本操作直接写
	int data;
	for (int i = 0; i < count; i++) {
		printf("请输入第%d个元素", i + 1);
		scanf("%d", &data);
		enQueue(sq, data, count + 1);
	}
	//接下来就是一次出队入栈啦
	for (int i = 0; i < count; ++i) {
		quitQueu(sq, &data, count + 1);
		//入栈
		push(s, data);//入栈操作(基本操作直接调用)
	}
	//出栈然后一次入队
	for (int i = 0; i < count; ++i) {
		data = *top(s);//查看栈顶元素的操作这里相当于把值赋值给局部变量
		pop(s);//出栈
		enQueue(sq, data, count + 1);//入队
	}
	return 1;//逆置完成
}

栈和队列的应用

第一题:

懒得敲了其实就是括号匹配的题目,我很早就写过一个直接用了

#define MAXSIZE 100//顺序栈最大长度

typedef char Elemtype;

typedef struct {
	Elemtype data[MAXSIZE];
	int top; 
	//栈顶指针,从0-》maxsize-1,-1表示空栈
	//也可以从1到maxsize,0表示空栈
}SeqStack,*PSeqStack;
void Clear(PSeqStack S) {
	if (S == NULL) return;
	S->top = -1;
	memset(S->data, 0, sizeof(Elemtype) * MAXSIZE);
}
void InitStack(PSeqStack S) {
	Clear(S);
}
int IsFull(PSeqStack S) {
	if (S == NULL) return 0;
	if (S->top >= MAXSIZE - 1) return 1;
	return 0;
}
int Push(PSeqStack S, Elemtype* ee) {
	if (S == NULL || ee == NULL) return 0;
	if (IsFull(S) == 1)  return 0;
	S->top++;
	memcpy(&S->data[S->top], ee, sizeof(Elemtype));
	return 1;
}
int Pop(PSeqStack S, Elemtype* ee) {
	if (S == NULL || ee == NULL) return 0;
	if (S->top == -1) return 0;//说明为空
	memcpy(ee, &S->data[S->top], sizeof(Elemtype));
	S->top--;
	return 1;
}

有了上述基本操作,接下来就是匹配算法了

int bracketmatch(char* str)
{
	SeqStack S;//创建顺序栈
	InitStack(&S);
	Elemtype ee;
	int ipos = 0, len = strlen(str);
	for (ipos = 0; ipos < len; ipos++) {
		//如果是左括号入栈
		if ((str[ipos] == '(') || (str[ipos] == '[') || (str[ipos] == '{'))
			Push(&S, &str[ipos]);
		//如果是右括号则出栈一个左括号并且判断是否匹配
		if ((str[ipos] == '}') || (str[ipos] = ']') || (str[ipos] == ')'))
		{
			if (Pop(&S, &ee) != 1) return 0;//判断出栈结果,如果栈中没有元素但还有右括号匹配失败
			//如果出现了不匹配的情况,函数返回
			if ((str[ipos] == ')') && (ee != '(')) return 0;
			if ((str[ipos] == ']') && (ee != '[')) return 0;
			if ((str[ipos] == '{') && (ee != '}')) return 0;
		}

	}
}
第二题:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u8MNOzSd-1657124775080)(D:\刷题图片\761)]

我的思路:

遇到软座直接通过,遇到硬座入栈直到软座出完再出栈

typedef struct Stack {
	char* arr;
	int len;
	int top;
}Stack;
void ArrangeTrain(char* arr, char* arrB, Stack* s,int len) {//len表示车长
	//声明函数方法
	int  push(Stack * , char k);
	int pop(Stack * );
	char* top(Stack * );//获取栈顶元素
	int IsEmpty(Stack*);
	int i = 0,j=0;
	while (i < len) {
		if (arr[i] == 'H') {
		//硬座入栈
			push(s, arr[i]);
		}
		else
		{
			//为软座直接过去
			arrB[j++] = arr[i];
		}
		i++;
	}
	//这时候硬座已经全部入栈了现在出栈就可
	char *c;//接受变量
	while (!IsEmpty(s)) {
		//只要还有就全部如B
		c = top(s);
		pop(s);
		arr[j++] = *c;
	}
}
第三题:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3SIzdC4-1657124775081)(D:\刷题图片\762)]

我的思路:

由于前两个值我们是知道的所以我们可以根据栈先进后出的性质,把最早知道的数最后放入也就是放在栈顶,然后依次出栈

typedef struct Countnum {
	int number;//第几个数
	int val;//值
}Countnum;
typedef struct Stack {
	Countnum* arr;
	int len;
	int top;
}Stack;
int GetFinal(Stack* s, int n, int x) {//传入未知参数x,n依题意
	if (n == 0) {
		return 1;
	}
	int val1 = 1, val2 = 2 * x;
	for (int i = n; i >= 2; --i) {
	//依次入栈
		s->top++;//默认初始化为-1
		s->arr[s->top].number = i;//表示放入的是第n个数,最底下放的是最后的计算的值
	}
	while (s->top>=0)
	{//出栈同时计算
		s->arr[s->top].val = 2 * x * val2 - 2 * (s->arr[s->top].number - 1) * val1;//按照公式照抄
		val1 = val2;
		val2 = s->arr[s->top].val;
		s->top--;
	}
	return val2;//最后反回的肯定是最后一个要赋值的数
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值