1. 链表模板
c
truct ListNode {
int val;
struct ListNode *next;
};
typedef struct MyLinkedList_t {
int val;
struct MyLinkedList_t *next;
} MyLinkedList;
void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val);
MyLinkedList *myLinkedListCreate()
{
// 在链表的第一个结点之前会额外增设一个结点,头结点
MyLinkedList *dummyHead = (MyLinkedList *)malloc(sizeof(MyLinkedList));
if (dummyHead == NULL) {
return NULL;
}
dummyHead->next = NULL;
dummyHead->val = 0; // 头结点的val用来指示链表长度
return dummyHead;
}
// 从头节点开始遍历,找到index对应的值并返回
int myLinkedListGet(MyLinkedList *obj, int index)
{
int cnt = 0;
MyLinkedList *tmp = obj->next;
while (tmp != NULL) {
if (index == cnt) {
return tmp->val;
}
tmp = tmp->next;
cnt++;
}
return -1;
}
void myLinkedListAddAtHead(MyLinkedList *obj, int val)
{
myLinkedListAddAtIndex(obj, 0, val);
}
void myLinkedListAddAtTail(MyLinkedList *obj, int val)
{
myLinkedListAddAtIndex(obj, obj->val, val);
}
// 插入节点
void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val)
{
int cnt = 0;
if (index > obj->val) {
// 1.索引大于长度
return;
}
// 2.索引插入节点
MyLinkedList *tmp = obj;
MyLinkedList *newNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
newNode->val = val;
while (tmp != NULL) {
if (cnt == index) {
break;
}
tmp = tmp->next;
cnt++;
}
newNode->next = tmp->next;
tmp->next = newNode;
obj->val++; // 记录链表长度
return;
}
// 删除节点
void myLinkedListDeleteAtIndex(MyLinkedList *obj, int index)
{
MyLinkedList *node = NULL;
MyLinkedList *tmp = obj;
int cnt = 0;
if (index >= obj->val) {
return; // 下标无效
}
while (tmp != NULL) {
if (cnt == index) {
break;
}
cnt++;
tmp = tmp->next;
}
if (tmp->next == NULL) { // 删除的是最后的NULL,直接返回,手法
return;
}
obj->val--;
node = tmp->next; // tmp->next为要删除的节点,tmp->next = tmp->next->next
tmp->next = node->next; // 这么操作是因为free(node)
free(node);
}
void myLinkedListFree(MyLinkedList *obj) {
MyLinkedList *tmp = obj;
MyLinkedList *freeNode;
while (tmp != NULL) { // 释放头结点->首元结点内的
freeNode = tmp;
tmp = tmp->next;
freeNode->next = NULL;
freeNode->val = 0;
free(freeNode);
}
}
int main()
{
int ret = 0;
MyLinkedList* obj = myLinkedListCreate();
myLinkedListAddAtHead(obj, 1);
myLinkedListAddAtTail(obj, 3);
myLinkedListAddAtIndex(obj, 1, 2);
ret = myLinkedListGet(obj, 1);
myLinkedListDeleteAtIndex(obj, 1);
ret = myLinkedListGet(obj, 1);
ret = myLinkedListGet(obj, 3);
myLinkedListDeleteAtIndex(obj, 3);
myLinkedListDeleteAtIndex(obj, 3);
ret = myLinkedListGet(obj, 0);
myLinkedListDeleteAtIndex(obj, 0);
ret = myLinkedListGet(obj, 0);
return 0;
}
2. 队列实现模板
c
#define MAX_NUN 1024
typedef struct {
int head;
int tail;
int size; // 计算队列元素个数
int data[MAX_NUN];
} Queue_t;
Queue_t *QueueCreate(int size)
{
Queue_t *queue = (Queue_t *)malloc(sizeof(Queue_t));
queue->tail = 0;
queue->head = 0;
queue->size = size;
memset(queue->data, 0, sizeof(int) * (MAX_NUN));
return queue;
}
bool QueuePush(Queue_t *queue, int value)
{
if (QueueIsFull(queue)) {
return false;
}
queue->data[queue->tail] = value; // 先入队
queue->tail = (queue->tail + 1) % queue->size; // tail再移动,队尾元素为tail-1.
return true;
}
bool QueuePop(Queue_t *queue, int *value)
{
if (QueueIsEmpty(queue)) {
return false;
}
*value = queue->data[queue->head];
queue->head = (queue->head + 1) % queue->size;
return true;
}
bool QueueIsEmpty(Queue_t *queue)
{
return (queue->head == queue->tail);
}
bool QueueIsFull(Queue_t *queue)
{
return (((queue->tail + 1) % queue->size) == queue->head);
}
int QueueFront(Queue_t *queue)
{
if (QueueIsEmpty(queue)) {
return -1;
}
return queue->data[queue->head];
}
int QueueTail(Queue_t *queue)
{
if (QueueIsEmpty(queue)) {
return -1;
}
return queue->data[(queue->tail - 1 + queue->size) % queue->size];
}
void QueueFree(Queue_t *queue)
{
free(queue);
queue = NULL;
}
3. 单调栈
c
int stack[size];
//此处一般需要给数组最后添加结束标志符,具体下面例题会有详细讲解
for (遍历这个数组)
{
if (栈空 || 栈顶元素大于等于当前比较元素)
{
入栈;
} else
{
while (栈不为空 && 栈顶元素小于当前元素)
{
栈顶元素出栈;
更新结果;
}
当前数据入栈;
}
}
什么是单调栈?
从名字上就听的出来,单调栈中存放的数据应该是有序的,所以单调栈也分为单调递增栈和单调递减栈
单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大
递增栈 :
pointer: bottom top
Index: 0 1 2 3
val: 60 20 20 10
栈底 - 《《《《《《《 - 栈顶(自顶向下为递增)
c
#define NUM_SIZE 10001
void GetNext(int *num, int size, int *res)
{
int top = 0;
int *stack = (int *)malloc(sizeof(int) * size);
memset(stack, 0, sizeof(int) * size);
for (int i = 0; i < size; i++) {
if ((top == 0) || (num[i] <= stack[top - 1])) {
stack[top] = num[i];
top++;
} else {
while ((top > 0) && (num[i] > stack[top - 1])) { // 如果此时比较元素大于栈顶元素,则栈顶元素出栈.
res[stack[top - 1]] = num[i]; // 将找到的元素作为map存下来.
top--;
}
stack[top] = num[i];
top++;
}
}
// 处理此时还未出栈的元素,都是不存在下一个更大元素的,赋值为-1。
while (top > 0) {
res[stack[top - 1]] = -1;
top--;
}
free(stack);
}
4. 字符串
判断字符串是否为数字(包括正负数)
c
if (sscanf(token, "%d", &num) == 1) { // 判断是否为数字的方法,包括正负数
*** = num; // 使用num
}
c
// 使用正则表达式,识别字符串
sscanf(logs[i], "%d:%[a-z]:%d", &idx, type, ×tamp); // 拆分字符串
- 常见用法。
char buf[512] ={0} ;
sscanf("123456 ", "%s", buf);
printf("%s/n", buf);
结果为:123456 - 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。
sscanf("123456 ", "%4s", buf);
printf("%s/n", buf);
结果为:1234 - 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。
sscanf("123456 abcdedf", "%[^ ]", buf);
printf("%s/n", buf);
结果为:123456 - 取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
printf("%s/n", buf);
结果为:123456abcdedf - 取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。
sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);
printf("%s/n", buf);
结果为:123456abcdedf
6、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
sscanf("iios/12DDWDFF@122", "%*[/]/%[@]", buf);
printf("%s/n", buf);
结果为:12DDWDFF
DFS模板
c
void dfs(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本节点所连接的其他节点) {
处理节点;
dfs(图,选择的节点); // 递归
回溯,撤销处理结果
}
}
BFS模板
c
nt dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 表示四个方向
// grid 是地图,也就是一个二维数组
// visited标记访问过的节点,不要重复访问
// x,y 表示开始搜索节点的下标
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
queue<pair<int, int>> que; // 定义队列
que.push({x, y}); // 起始节点加入队列
visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点
while(!que.empty()) { // 开始遍历队列里的元素
pair<int ,int> cur = que.front(); que.pop(); // 从队列取元素
int curx = cur.first;
int cury = cur.second; // 当前节点坐标
for (int i = 0; i < 4; i++) { // 开始想当前节点的四个方向左右上下去遍历
int nextx = curx + dir[i][0];
int nexty = cury + dir[i][1]; // 获取周边四个方向的坐标
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 坐标越界了,直接跳过
if (visited[nextx][nexty] == 0) { // 如果节点没被访问过
que.push({nextx, nexty}); // 队列添加该节点为下一轮要遍历的节点
visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
}
}
}
}