排序、KMP算法、队列、栈
一、希尔排序
1.初次取序列的一半为增量,以后每次减半,直到增量为1(round(n/2)--->1)
2.每组遍历
3.组内排序
1 //希尔排序 2 int shell_sort(int *data, int len) 3 { 4 int gap = 0; 5 int i = 0, j = 0; 6 for (gap = len / 2; gap >= 1; gap / 2) //增量---->外层步长控制 7 { 8 for (i = gap; i < len; i++) //每组遍历 9 { 10 int temp = data[i]; 11 for (j = i - gap; j >= 0 && temp < data[j]; j = j - gap) //组内排序 12 { 13 data[j + gap] = data[j]; 14 } 15 data[j + gap] = temp; 16 } 17 } 18 19 return 0; 20 }
二、快速排序
1.第一个值为哨兵,从后面往前面找,找到比它小的,然后替换;从前面往后面找,找到比它大的,然后替换;
2.然后以第一个key为基准,数据分为两部分,分别是key的左边部分和key右边部分;分别对这两部分的数据进行递归;
//快速排序 int sort(int *data, int left, int right) //每一次递归, 每调用一次, 确定一个key的正确位置 { if (left >= right) return 0; int i = left; int j = right; int key = data[left]; while (i < j) //保证出现i==j,即确定了key的位置 { while (i < j && key < data[j]) //从后面往前面走,找到小于key的值,然后替换 { j--; } data[i] = data[j]; while (i < j && key >= data[i]) //从前面往后面走,找到大于key的值,然后替换 { i++; } data[j] = data[i]; } //i == j,此时确定了key的所在顺序的正确位置 data[i] = key; //递归 sort(data, left, i - 1); sort(data, i + 1, right); return 0; } int quick_sort(int *data, int len) { sort(data, 0, len - 1); return 0; }
三、链表常考知识点
1.单向链表如何找到倒数n个节点
双指针法:
(1) p2往后移动N个节点,此时p1和p2之间的距离刚好为N
(2) 同时往后移动p1,p2,当p2是尾节点时,p1刚好移动到倒数第N个节点
struct Node { int data; struct Node *next; }; struct Node *lastNode(struct Node *head, int n) { struct Node *p1; struct Node *p2; p1 = head; p2 = head; int k = n; while ((k > 1) && (p2 != NULL)) { p2 = p2->next; k--; } if (p2 == NULL) /*说明链表数目不足n个*/ { return head; } while (p2->next != NULL) //双指针移动,当p2是尾节点时,p1刚好移动到倒数第N个节点 { p2 = p2->next; p1 = p1->next; } return p1; }
2.判断链表是否有环?
快慢指针法:
(1)慢指针slow每次往前走一步(slow = slow->next),快指针fast每次往前走两步(fast = fast->next->next);
(2)如果有环,fast一定会先进入环,而slow后进入环。当两个指针都进入环之后,经过一定步的操作之后二者一定能够在环上相遇;
int has_cycle(struct Node *head) { struct Node *fast = head; struct Node *low = head; while (fast != NULL && fast->next != NULL) { low = low->next; fast = fast->next->next; if (low == fast) { return 1; } } return 0; }
3.判断两个链表是否交叉,并返回交点
双指针移动法:
长的链表先走abs(len1 - len2)步,此时两个链表剩余的长度一样长,两个链表再同时往后移动,如果有相等则相交;
struct Node *intersect_list(struct Node *headA, struct Node *headB) { struct Node *p1 = headA, *p2 = headB; int len1 = 0, len2 = 0; while (p1) p1 = p1->next, len1++;//获取长度 while (p2) p2 = p2->next, len2++; int diff = abs(len1 - len2); struct Node *big = len1 >= len2 ? headA : headB;//取得长的链表 while (diff--) big = big->next; struct Node *small = len1 < len2 ? headA : headB; //取得短的链表 while (big != small) //两个链表再同时往后移动,如果有相等则相交 { big = big->next; small = small->next; } return small; }
4.链表反转
就地反转,一个头节点,两个指针。
struct Node *reverse_list(struct Node *head) { if (head == NULL) { return head; } //新建一个空头节点,连接 head节点 struct Node *dummy; dummy->data = -1; dummy->next = head; //新建两个指针 struct Node *prev = dummy->next; struct Node *pCure = prev->next; while (pCure != NULL) { prev->next = pCure->next; //prev连接下一次需要反转的节点,相当于断开pCure,与上一个和下一个节点的连接 pCure->next = dummy->next; //反转节点pCur,即指向的是prev节点 dummy->next = pCure; //纠正头结点,指向当前的节点pCur pCure = prev->next; //pCur指向下一次要反转的节点 } return dummy->next; }
四、KMP算法
字符串匹配算法
(1)求出公共部分最长的长度;
(2)下一次对比数组(next数据)
void make_next(const char *pattern, int *next) { int q, k; int m = strlen(pattern); next[0] = 0; for (q = 1, k = 0; q < m; q++) { while (k > 0 && pattern[q] != pattern[k]) { k = next[k - 1]; } if (pattern[q] == pattern[k]) { k++; } next[q] = k; } } int kmp(const char *text, const char *pattern, int *next) { int n = strlen(text); int m = strlen(pattern); make_next(pattern, next); int i, q; for (i = 0, q = 0; i < n; i++) { #if 1 while (q > 0 && pattern[q] != text[i]) { q = next[q - 1]; } #endif if (pattern[q] == text[i]) { q++; } if (q == m) { return i - q + 1; } } return -1; } int main() { char *text = "abcabcabcabcabcd"; char *pattern = "abcabcd"; int next[20] = {0}; int idx = kmp(text, pattern, next); printf("match pattern:%d\n", idx); return 0; }