数据结构1—希尔,KMP,链表简单题
业务代码写了几个月,深感脱离了业务,感觉不剩下啥,特此进行一些基础复习。
希尔排序
希尔排序的核心思想:分组+插排
-
分组
以gap = length / 2分组,从第一个元素开始,每间隔gap个元素划分为一组,以此类推。当gap为1时,即每组剩余一个元素,此时排序完成。
-
组内排序
通过插入排序来对每组元素进行排序。
/*
* @param
* data : data
* length: length of data
* @return
* 0:sucess
*/
int shell_sort(int *data, int length) {
int gap = 0;
int i = 0, j = 0;
for (gap = length / 2; gap >= 1; gap /= 2) { // 分组次数
for (i = gap; i < length; i++) { // 从第gap个元素开始,对其再其对应组内做插入排序
int temp = data[i];
for (j = i - gap; j >= 0 && temp < data[j]; j = j - gap) { //组内排序
data[j + gap] = data[j];
}
data[j + gap] = temp;
}
}
return 0;
}
实现细节:
第二个循环:从第gap个元素开始,对于每个元素,都在对应组内做插入排序。data[gap]在第一组,data[gap + 1] 在第二组,以此类推。data[0]与data[gap]先做插入排序,以此类推。在2 * gap个元素的时候,data[0],data[gap]已经排好序了,继续插入即可。
快速排序
老生常谈。每次确定一个元素位置,分治法递归即可。
int sort(int *data, int left, int right) {
if (left >= right) {
return 0;
}
int i = left;
int j = right;
int key = data[left];
while (i < j) {
while (i < j && key < data[j]) j--;
data[i] = data[j];
while (i < j && key >= data[i]) i++;
data[j] = data[i];
}
// i==j
data[i] = key;
sort(data, left, i - 1);
sort(data, i + 1, right);
}
int quick_sort(int *data, int length) {
sort(data, 0, length);
}
KMP
KMP算法其实在算法导论里讲的更好(我这只是挂个代码,稀碎的解释可以不用看啦)next数组其实对应着含义不同其实现也不同。
Pattern: abcabcd,后面简称P
Target: abcabcabcabcabcd,后面简称T
预备知识:前缀和后缀。
例如abca
- 前缀:不包含最后一个字符的前面连续字串 (a,ab,abc)
- 后缀:不包含第一个字符的后面的连续字串 (a,cd ,bcdc)
核心思想:利用已经部分匹配这个有效信息,让模式串尽量地移动到有效的位置。每次移动相同前后缀的最大长度。
用公式来看就是这样
P[0 ~ k-1] == P[j-k ~ j-1]
next:模式串下一次移动长度数组。next[j] = k,P[0~j]中最长相同前后缀长度。
//abcabc
//k = 0
/ q = 1
void make_next(const char *pattern, int *next) {
int q, k; //k 前缀,q后缀下标
int m = strlen(pattern);
next[0] = 0; // 初始化
for (q = 1, k = 0; q < m; q++) {
// PS 可以动手画一下
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++) {// i --> text, q --> pattern
while (q > 0 && pattern[q] != text[i]) {
q = next[q - 1];
}
if (pattern[q] == text[i]) {
q++;
}
if (q == m) {
return i - q + 1;
}
}
}
几道leetcode简单链表题,老生常谈的题目就直接放代码啦。
1.单向链表寻找倒K节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
if (!head) {
return 0;
}
ListNode *slow = head, *fast = head;
while (k-- && fast){
fast = fast->next;
}
while(k-- && fast) {
slow = slow->next;
fast = fast->next;
}
return slow->val;
}
};
2.判断链表有无环
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return true;
}
}
return false;
}
};
3.链表相交
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *A = headA;
ListNode *B = headB;
if(!headA||!headB){
return NULL;
}
while(headA != headB)
{
headA = headA == NULL ? B : headA->next;
headB = headB == NULL ? A : headB->next;
}
return headA;
}
};
4.反转链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *pre = NULL;
ListNode *now = head;
while(now)
{
ListNode *tmp = now->next;
now->next = pre;
pre = now;
now = tmp;
}
return pre;
}
};