考研数据结构程序题常见代码【C语言实现】

考研院校要求C语言实现数据结构,可前期做数据结构都是用Java实现,因此对于C不那么熟悉,花了一些时间重新捡起来C的语法,程序题通常不会考太过复杂的算法,现整理如下👇

1. 链表

1.1 结构体实现链表样例

#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
	int num;
	struct Node* next;
} Node;
//创建一个数值为i的节点并插入在节点p后边
void insert(Node* p, int i) {
	//指针指向Node这么大的空间
	Node* temp = malloc(sizeof(Node));
	temp->next = NULL;
	temp->num = i;
	p->next = temp;
}
int main() {
	Node* node = malloc(sizeof(Node));
	node->num = 1;
	node->next = NULL;
	insert(node, 10);
	while (node != NULL) {
		printf("%d ", node->num);
		node = node->next;
	}
}

1.2 头插尾插与反转

#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
	int val;
	struct Node* next;
} Node;
//头插法
void InsertNode(Node* head, Node* p);
//尾插法
void InsertNodeBehind(Node* head, Node* p);
//链表反转 (递归实现)
void reverseList(Node* head, Node* temp);
//头插法实现链表反转
void reverseList2(Node* head);

int main() {
	Node* head = malloc(sizeof(Node));
	head->val = -1;
	head->next = NULL; //初始化很重要
	for (int i = 1; i <= 10; i++) {
		Node* temp = malloc(sizeof(Node));
		temp->val = i;
		temp->next = NULL;
		// 尾插
		InsertNodeBehind(head, temp);
	}
	// 头插法实现反转
	reverseList2(head);
	head = head->next;
	while (head != NULL) {
		printf("%d ", head->val);
		head = head->next;
	}
}

void InsertNode(Node* head, Node* p) {
	p->next = head->next;
	head->next = p;
}

void InsertNodeBehind(Node* head, Node* p) {
	Node* temp = head;
	while (temp->next != NULL) {
		temp = temp->next;
	}
	temp->next = p;
}

void reverseList(Node* head, Node* temp) {
	if (temp->next == NULL) {
		head->next = temp;
		return;
	} else if (temp->next != NULL) {
		reverseList(head, temp->next);
		temp->next->next = temp;
		temp->next = NULL;
	}
}

void reverseList2(Node* head) {
	if (head->next == NULL || head->next->next == NULL) {
		return;
	}
	Node* p = head->next->next;
	head->next->next = NULL;
	Node* p1;
	while (p) {
		p1 = p->next;
		p->next = head->next;
		head->next = p;
		p = p1;
	}
}

2. 树

image-20230320095228591

2.1 树的遍历

2.1.1 前中后序遍历

#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
	int val;
	struct Node* left;
	struct Node* right;
} Node;
void initial();
// 前序遍历
void prePrint(Node* root);
// 中序遍历
void midPrint(Node* root);
// 后序遍历
void lastPrint(Node* root);
// 树的高度
int getHeight(Node* root);
Node *root, *node1, *node2, *node3, *node4, *node5, *node6, *node7;
int main() {
	// 初始化很重要
	initial();
	printf("前序遍历序列为:");
	prePrint(root);
	printf("\n中序遍历序列为:");
	midPrint(root);
	printf("\n后序遍历序列为:");
	lastPrint(root);
	printf("\n树的高度是:%d", getHeight(root));
}
//树的高度
int getHeight(Node* root) {
	if (root == NULL) {
		return 0;
	}
	int a = getHeight(root->left) + 1;
	int b = getHeight(root->right) + 1;
	return a > b ? a : b;
}
//前序遍历
void prePrint(Node* root) {
	printf("%d ", root->val);
	if (root->left != NULL) {
		prePrint(root->left);
	}
	if (root->right != NULL) {
		prePrint(root->right);
	}
}
//中序遍历
void midPrint(Node* root) {
	if (root->left != NULL) {
		midPrint(root->left);
	}
	printf("%d ", root->val);
	if (root->right != NULL) {
		midPrint(root->right);
	}
}
//后序遍历
void lastPrint(Node* root) {
	if (root->left != NULL) {
		lastPrint(root->left);
	}
	if (root->right != NULL) {
		lastPrint(root->right);
	}
	printf("%d ", root->val);
}
void initial() {
	root = malloc(sizeof(Node));
	node1 = malloc(sizeof(Node));
	node2 = malloc(sizeof(Node));
	node3 = malloc(sizeof(Node));
	node4 = malloc(sizeof(Node));
	node5 = malloc(sizeof(Node));
	node6 = malloc(sizeof(Node));
	node7 = malloc(sizeof(Node));

	root->val = 0;
	node1->val = 1;
	node2->val = 2;
	node3->val = 3;
	node4->val = 4;
	node5->val = 5;
	node6->val = 6;
	node7->val = 7;

	root->left = node1;
	root->right = node2;
	node1->left = node3;
	node1->right = node4;
	node2->left = node5;
	node2->right = node6;
	node3->left = node7;
	node3->right = NULL;
	node4->left = NULL;
	node4->right = NULL;
	node5->left = NULL;
	node5->right = NULL;
	node6->left = NULL;
	node6->right = NULL;
	node7->left = NULL;
	node7->right = NULL;
}

2.1.2 层次遍历

层次遍历需要使用队列queue,而C语言中没有现成的队列可以调用,因此此处实现使用了少许C++的代码,如结构体中的构造函数,分配空间使用new语法【malloc仅仅分配空间而不会调用构造函数,C++中需要调用构造函数才能为结构体(或对象)申请内存空间,因此只能用new而不能用malloc

若院校要求C语言实现,则写试卷时用注释交代一下队列的情况、内置的方法情况即可拿来使用

#include<stdio.h>
#include<queue>
using namespace std;
typedef struct Node {
	int val;
	Node* left;
	Node* right;
	Node(int val, Node* left, Node* right) {
		this->val = val;
		this->left = left;
		this->right = right;
	}
} Node;
void initial();
void rowPrint(Node *root);
Node *root, *node1, *node2, *node3, *node4, *node5, *node6, *node7;
queue<Node*> q;
int main() {
	initial();
	printf("层序遍历次序为:");
	rowPrint(root);
}
//层序遍历
void rowPrint(Node* root) {
	q.push(root);
	while (!q.empty()) {
		int n = q.size();
		for (int i = 0; i < n; i++) {
			Node *temp = q.front();
			if (temp->left != NULL) {
				q.push(temp->left);
			}
			if (temp->right != NULL) {
				q.push(temp->right);
			}
			printf("%d ", temp->val);
			q.pop();
		}
	}
}
void initial() {
	// 需要保证传入参数时对象已经构建,所以对执行顺序有要求
	// 此处为了节省篇幅而采用C++的构造函数,C语言只能按照??2.1.1的initial函数中的方法初始化
	node4 = new Node(4, NULL, NULL);
	node5 = new Node(5, NULL, NULL);
	node6 = new Node(6, NULL, NULL);
	node7 = new Node(7, NULL, NULL);
	node3 = new Node(3, node7, NULL);
	node1 = new Node(1, node3, node4);
	node2 = new Node(2, node5, node6);
	root = new Node(0, node1, node2);
}

2.2 二叉排序树

image-20230320144029448
#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
	int val;
	struct Node* left;
	struct Node* right;
} Node;
Node *root, *node1, *node2, *node3, *node5, *node6, *node7;
// 中序遍历
void midPrint(Node* root);
// 往二叉排序树插入结点
void insertNode(Node* root, Node* temp);
// 初始化
void initial();
// 递归查找某个值对应的节点
Node* searchByVal(Node* root, int val);
// 非递归查找
Node* searchByVal2(Node* root, int val);
int main() {
	initial();//初始化
	printf("中序输出二叉排序树:");
	midPrint(root);
	Node* temp = searchByVal(root, 5);
	printf("\n%c", temp == NULL ? 'F' : 'T');
}

Node* searchByVal(Node* root, int val) {
	if (root == NULL) {
		return NULL;
	} else if (root->val == val) {
		return root;
	} else if (root->val < val) {
		return searchByVal(root->right, val);
	} else {
		return searchByVal(root->left, val);
	}
}

Node* searchByVal2(Node* root, int val) {
	while (root != NULL) {
		if (root->val == val) {
			return root;
		} else if (root->val < val) {
			root = root->right;
		} else {
			root = root->left;
		}
	}
	return NULL;
}

void insertNode(Node* root, Node* temp) {
	if (temp->val < root->val) {
		if (root->left != NULL) {
			insertNode(root->left, temp);
		} else {
			root->left = temp;
		}
	} else {
		if (root->right != NULL) {
			insertNode(root->right, temp);
		} else {
			root->right = temp;
		}
	}
}

void midPrint(Node* root) {
	if (root->left != NULL) {
		midPrint(root->left);
	}
	printf("%d ", root->val);
	if (root->right != NULL) {
		midPrint(root->right);
	}
}

void initial() {
	root = malloc(sizeof(Node));
	node1 = malloc(sizeof(Node));
	node2 = malloc(sizeof(Node));
	node3 = malloc(sizeof(Node));
	node5 = malloc(sizeof(Node));
	node6 = malloc(sizeof(Node));
	node7 = malloc(sizeof(Node));

	root->val = 4;
	node1->val = 1;
	node2->val = 2;
	node3->val = 3;
	node5->val = 5;
	node6->val = 6;
	node7->val = 7;

	root->left = NULL;
	root->right = NULL;
	node1->left = NULL;
	node1->right = NULL;
	node2->left = NULL;
	node2->right = NULL;
	node3->left = NULL;
	node3->right = NULL;
	node5->left = NULL;
	node5->right = NULL;
	node6->left = NULL;
	node6->right = NULL;
	node7->left = NULL;
	node7->right = NULL;

	insertNode(root, node2);
	insertNode(root, node6);
	insertNode(root, node1);
	insertNode(root, node3);
	insertNode(root, node5);
	insertNode(root, node7);
}

2.3 顺序存储二叉树与链式二叉树转换

此处用到queue,同样使用到了部分C++语法,若怕搞不清哪些是C的语法,哪些是C++语法,可以在执行文件时候保存为.c后缀的文件再编译运行【C++后缀是.cpp】,此时不属于C的语法就会报错

#include<stdio.h>
#include<stdlib.h>
#include<queue>
using namespace std;
typedef struct Node {
	int val;
	int in; //在数组中哪个下标
	Node* left;
	Node* right;
	Node(int val, int in, Node* left, Node* right) {
		this->val = val;
		this->in = in;
		this->left = left;
		this->right = right;
	}
} Node;

queue<Node*> list;
// 返回当前节点右孩子
int rChild (int index, int n, int arr[]);
// 返回当前节点左孩子
int lChild (int index, int n, int arr[]);
// 顺序二叉树的先序遍历
void prePrint(int index, int arr[], int n);
// 链式二叉树先序遍历
void prePrint2(Node* root);
// 顺序二叉树的广度遍历直接for遍历数组即可,省略实现
void BFS(int, int[], int);
// 创建一个节点
Node* indexToNode(int index, int arr[]);
// 将顺序存储二叉树转换为链式存储二叉树,返回根节点
Node* arrToList(int arr[], int n);

int main() {
	// 顺序存储时下标0不存储结点,从 1 开始存储
	// 此时若当前结点的下标为index,则其左孩子下标为 2*index,右孩子下标为 2*index + 1
	int arr[] = {-1, 52, 30, 68, 20, 50, 60, 70};
	// 得到数组长度
	int n = sizeof(arr) / sizeof(arr[0]);
	printf("顺序存储的前序遍历:");
	prePrint(1, arr, n);
	printf("\n\n链式存储的前序遍历:");
	Node* root = arrToList(arr, n);
	prePrint2(root);
}

Node* arrToList(int arr[], int n) {
	Node* root = indexToNode(1, arr);
	list.push(root);
	while (!list.empty()) {
		Node* temp = list.front();
		list.pop();
		// 当前节点对应左节点下标
		int left = lChild(temp->in, n, arr);
		if (left != -1) {
			Node* lNode = indexToNode(left, arr);
			temp->left = lNode;
			list.push(lNode);
		}
		// 当前节点对应右节点下标
		int right = rChild(temp->in, n, arr);
		if (right != -1) {
			Node* rNode = indexToNode(right, arr);
			temp->right = rNode;
			list.push(rNode);
		}
	}
	return root;
}

Node* indexToNode(int index, int arr[]) {
	Node* root = new Node(arr[index], index, NULL, NULL);
	return root;
}

void prePrint(int index, int arr[], int n) {
	if (arr[index] != -1) {
		printf("%d ", arr[index]);
	}
	// 根据index指向的结点左孩子的下标
	int left = lChild(index, n, arr);
	if (left != -1) {
		prePrint(left, arr, n);
	}
	// 根据index指向的结点右孩子的下标
	int right = rChild(index, n, arr);
	if (right != -1) {
		prePrint(right, arr, n);
	}
}

int lChild (int index, int n, int arr[]) {
	int lIndex = index * 2;
	if (lIndex < n && arr[lIndex] != -1) {
		return lIndex;
	} else {
		return -1;
	}
}

int rChild (int index, int n, int arr[]) {
	int rIndex = (index * 2) + 1;
	if (rIndex < n && arr[rIndex] != -1) {
		return rIndex;
	} else {
		return -1;
	}
}

//链式前序遍历
void prePrint2(Node* root) {
	if (root == NULL) {
		return;
	}
	printf("%d ", root->val);
	prePrint2(root->left);
	prePrint2(root->right);
}

3. 排序

快速排序与归并排序

#include<stdio.h>
#include<stdlib.h>
// 快速排序
void QuickSort(int [], int, int);
// 快速排序中每次确定的索引位置
int returnIndex(int [], int, int);

// 归并排序
void MergeSort(int [], int, int, int);
// 将一分为二排好序的数组进行最终排序
void Merge(int [], int, int, int);

int main() {
	int arr[] = {5, 7, 4, 8, 9, 2, 1, 3, 6};
	// 得到数组长度
	int n = sizeof(arr) / sizeof(int);
	printf("排序前的数组为:");
	for (int i = 0; i < n; i++) {
		printf("%d ", arr[i]);
	}
	// QuickSort(arr,0,n-1);
	MergeSort(arr, 0, n - 1, n);
	printf("\n\n排序后的数组为:");
	for (int i = 0; i < n; i++) {
		printf("%d ", arr[i]);
	}
}

void MergeSort(int arr[], int left, int right, int length) {
	if (left < right) {
		int mid = (left + right) / 2;
		MergeSort(arr, left, mid, length);
		MergeSort(arr, mid + 1, right, length);
		Merge(arr, left, right, length);
	}
}
void Merge(int arr[], int left, int right, int length) {
	// 创建一个数组,大小与arr一致
	// C语言规定数组大小时不允许传入变量,因此此处用指针“曲线救国”
	int* temp = malloc(length * sizeof(int));
	int mid = (left + right) / 2;
	for (int i = left; i <= right; i++) {
		temp[i] = arr[i];
	}
	int index = left, i = left, j = mid + 1;
	while (i <= mid && j <= right) {
		if (temp[i] > temp[j]) {
			arr[index++] = temp[j++];
		} else {
			arr[index++] = temp[i++];
		}
	}
	while (i <= mid) {
		arr[index++] = temp[i++];
	}
	while (j <= right) {
		arr[index++] = temp[j++];
	}
}

void QuickSort(int arr[], int left, int right) {
	if (left < right) {
		int mid = returnIndex(arr, left, right);
		QuickSort(arr, left, mid - 1);
		QuickSort(arr, mid + 1, right);
	}
}
int returnIndex(int arr[], int left, int right) {
	int temp = arr[left];
	while (left < right) {
		while (left < right && arr[right] >= temp) {
			right--;
		}
		arr[left] = arr[right];
		while (left < right && arr[left] <= temp) {
			left++;
		}
		arr[right] = arr[left];
	}
	arr[left] = temp;
	return left;
}

4. 查找

二分查找

#include<stdio.h>
// 递归方式的二分查找
int HalfSearch(int left, int right, int arr[], int target);
// 非递归方式的二分查找
int HalfSearch2(int left, int right, int arr[], int target);

int main() {
	int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
	int n = sizeof(arr) / sizeof(int);
	int index = HalfSearch2(0, n - 1, arr, 4);
	printf("目标位置索引为:%d", index);
}

int HalfSearch(int left, int right, int arr[], int target) {
	if (left > right) {
		return -1;
	}
	// 中间索引
	int midIndex = (left + right) / 2;
	// 中间值
	int mid = arr[midIndex];
	if (target == mid) {
		return midIndex;
	} else if (target < mid) {
		return HalfSearch(left, midIndex - 1, arr, target);
	} else {
		return HalfSearch(midIndex + 1, right, arr, target);
	}
}

int HalfSearch2(int left, int right, int arr[], int target) {
	int index = -1;
	while (left <= right) {
		// 中间索引
		index = (left + right) / 2;
		// 中间值
		int mid = arr[(left + right) / 2];
		if (target == mid) {
			return index;
		} else if (target < mid) {
			right = index - 1;
		} else {
			left = index + 1;
		}
	}
	return index;
}

5. 图

邻接表代码较多,估计不好出考试题

邻接矩阵

image-20230320154105749
#include<stdio.h>
#include<stdlib.h>
#include<queue>
#define MAX 10
using namespace std;
typedef struct Graph {
	// 顶点表
	int Vex[MAX];
	// 邻接矩阵
	int Edge[MAX][MAX];
	// 顶点数和弧数
	int vexNum, arcNum;
	// 节点是否访问,初始全为 false,即未被访问
	bool Visited[MAX] = {false};
	Graph() {
		// 初始顶点数为 0
		vexNum = 0;
		// 初始边数为 0
		arcNum = 0;
	}
} Graph;
Graph *g;
queue<int> q;
// 初始化顶点表,矩阵等信息
void initial();
// 无向图插入边
void insertEdge(int, int, int);
// 广度优先遍历
void DFS(int);
// 深度优先遍历
void BFS(int);
int main() {
	initial();
	printf("深度优先遍历:");
	// 从结点 1 出发
	DFS(1);
	initial();
	printf("\n广度优先遍历:");
	BFS(1);
}

void BFS(int index) {
	q.push(index);
	g->Visited[index] = true;
	while (!q.empty()) {
		int n = q.size();
		for (int i = 0; i < n; i++) {
			int j = q.front();
			q.pop();
			printf("%d ", g->Vex[j]);
			for (int x = 0; x < MAX; x++) {
				if (g->Edge[j][x] != 0 && g->Visited[x] == false) {
					q.push(g->Vex[x]);
					// 放进队列就相当于访问过
					g->Visited[x] = true;
				}
			}
		}
	}
}

void DFS(int index) {
	printf("%d ", g->Vex[index]);
	g->Visited[index] = true;
	for (int i = 0; i < MAX; i++) {
		if (g->Edge[index][i] != 0 && g->Visited[i] == false) {
			DFS(i);
		}
	}
}

void insertEdge(int Vex1, int Vex2, int Power) {
	// 无向图添两边
	g->Edge[Vex1][Vex2] = Power;
	g->Edge[Vex2][Vex1] = Power;
}

void initial() {
	g = new Graph;
	for (int i = 0; i < MAX; i++) {
		for (int j = 0; j < MAX; j++) {
			g->Edge[i][j] = 0; //此时顶点i与j之间没有通路
		}
		g->Vex[i] = i; //0~9号顶点
	}
	// 顶点1与顶点2之间有通路
	insertEdge(1, 2, 1);
	insertEdge(1, 4, 1);
	insertEdge(2, 3, 1);
	insertEdge(3, 5, 1);
	insertEdge(5, 2, 1);
	insertEdge(4, 3, 1);
}

总结

这些整理希望能够帮助到你们,祝你们考研成功!

  • 11
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值