您的位置:首页 > 编程语言

15个使用频率极高的基础算法题(附完整代码)

2014-08-23 13:51 399 查看

合并排序,将两个已经排序的数组合并成一个数组,其中一个数组能容下两个数组的所有元素

一般来说,合并两个已经有序的数组,首先是开一个能存的下两个数组的第三个数组,但是题目中已经说了,其中一个数组能全部存的下,显然就不应该浪费空间了。

从前往后扫的话,数据要存在大数组的前头,这样每次要把大数组的元素一次后移一位,显然不是什么好主意,所以我们从后往前存。

[cpp] view
plaincopyprint?

#include<iostream>

#include<cstdlib>

using namespace std;

int cc[10];

int tt[5];

void init()

{

srand((unsigned)time(NULL));

int num = rand() % 5;

for(int i = 0; i < 5; i++)

{

cc[i] = num;

num += rand() % 10 + 1;

}

num = rand() % 5;

for(int i = 0; i < 5; i++)

{

tt[i] = num;

num += rand() % 10 + 1;

}

}

void merge()

{

int i = 4, j = 4, idx = 9;

while(i>=0 && j>=0)

{

if(cc[i] > tt[j])

cc[idx--] = cc[i--];

else

cc[idx--] = tt[j--];

}

while(i>=0)

cc[idx--] = cc[i--];

while(j>=0)

cc[idx--] = tt[j--];

}

int main()

{

init();

for(int i = 0; i < 5; i++)

printf("%d ", cc[i]);

putchar(10);

for(int i = 0; i < 5; i++)

printf("%d ", tt[i]);

putchar(10);

merge();

for(int i = 0; i < 10; i++)

printf("%d ", cc[i]);

putchar(10);

getchar();

return 0;

}

合并两个已经排序的单链表

不能创建第三条链表,用上两种办法进行合并

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

struct node{

int data;

node *next;

};

void CreateNode(node *head) // 创建带有头结点的有序单链表

{

node *s = head;

int val = rand() % 5 + 1;

for (int i = 0; i < 5; i++)

{

val += rand() % 5 + 1;

node *t = new node;

t->data = val;

t->next = NULL;

s = s->next = t;

}

}

void PrintNode(node *head)

{

node *s = head;

while (s = s->next)

printf("%d ", s->data);

putchar(10);

}

node* Merge_1(node *head1, node *head2) // 顺序扫描

{

node *i = head1->next;

node *j = head2->next;

node *cc = new node;

node *s = cc;

while(i && j)

{

if(i->data < j->data)

{

s = s->next = i;

i = i->next;

}

else

{

s = s->next = j;

j = j->next;

}

}

if(i)

s->next = i;

else

s->next = j;

return cc;

}

node* Merge_2(node *head1, node *head2) // 递归法

{

if(head1 == NULL)

return head2;

if(head2 == NULL)

return head1;

node *cc = NULL;

if(head1->data < head2->data)

{

cc = head1;

cc->next = Merge_2(head1->next, head2);

}

else

{

cc = head2;

cc->next = Merge_2(head1, head2->next);

}

return cc;

}

int main()

{

srand((unsigned)time(NULL));

node *LinkList1 = new node, *LinkList2 = new node;

CreateNode(LinkList1);

CreateNode(LinkList2);

PrintNode(LinkList1);

PrintNode(LinkList2);

// LinkList1 = Merge_1(LinkList1, LinkList2);

LinkList1->next = Merge_2(LinkList1->next, LinkList2->next);

PrintNode(LinkList1); // 合并后的链表存在1中

getchar();

return 0;

}

倒序打印一个单链表

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

struct node{

int data;

node *next;

};

void CreateNode(node *&head) // 创建不带头结点的有序单链表

{

head = new node;

head->data = rand() % 5 + 1;

node *s = head, *t = NULL;

for(int i = 0; i < 5; i++)

{

t = new node;

t->data = s->data + rand() % 5 + 1;

s = s->next = t;

}

s->next = NULL;

}

void PrintNode(node *head)

{

node *s = head;

while (s != NULL)

{

printf("%d ", s->data);

s = s->next;

}

putchar(10);

}

void PrintNode_Reverse(node *head)

{

if(head->next != NULL)

PrintNode_Reverse(head->next);

printf("%d ", head->data);

}

int main()

{

srand((unsigned)time(NULL));

node *LinkList;

CreateNode(LinkList);

PrintNode(LinkList);

PrintNode_Reverse(LinkList);

putchar(10);

getchar();

return 0;

}

给定一个单链表的头指针和一个指定节点的指针,在O(1)时间删除该节点

参见博客:如何在O(1)的时间里删除单链表的结点

找到链表倒数第K个节点

设两个指针,一个先向前走K步,然后两个指针同步移动,等先走的指针走到了末尾,后走的指针就在倒数第K个位置了。

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

struct node{

int data;

node *next;

};

void CreateNode(node *&head) // 创建不带头结点的有序单链表

{

head = new node;

head->data = rand() % 5 + 1;

node *s = head, *t = NULL;

for(int i = 0; i < 10; i++)

{

t = new node;

t->data = s->data + rand() % 5 + 1;

s = s->next = t;

}

s->next = NULL;

}

void PrintNode(node *head)

{

node *s = head;

while (s != NULL)

{

printf("%d ", s->data);

s = s->next;

}

putchar(10);

}

void find(node *head, int num)

{

node *s = head, *t = head;

for(int i = 0; i < num; i++)

t = t->next;

while(t)

{

s = s->next;

t = t->next;

}

printf("place: %dth value:%d\n", num, s->data);

}

int main()

{

srand((unsigned)time(NULL));

node *LinkList;

CreateNode(LinkList);

PrintNode(LinkList);

find(LinkList, 5);

find(LinkList, 3);

putchar(10);

getchar();

return 0;

}

反转单链表

用递归与非递归两种方法,注意检查链表只有一个结点的时候反转函数不会出错

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

struct node{

int data;

node *next;

};

void CreateNode(node *&head) // 创建不带头结点的有序单链表

{

head = new node;

head->data = rand() % 5 + 1;

node *s = head, *t = NULL;

for(int i = 0; i < 10; i++)

{

t = new node;

t->data = s->data + rand() % 5 + 1;

s = s->next = t;

}

s->next = NULL;

}

void PrintNode(node *head)

{

node *s = head;

while (s != NULL)

{

printf("%d ", s->data);

s = s->next;

}

putchar(10);

}

node* Reverse_1(node *head) // 非递归

{

node *s = head, *t = head->next;

s->next = NULL;

while(t != NULL)

{

node *r = t->next;

t->next = s;

s = t;

t = r;

}

return s;

}

void Reverse_2(node *front, node *n, node *&head) // 递归

{

front->next = NULL;

if(n != NULL)

head = n;

if(n != NULL && n->next != NULL)

Reverse_2(n, n->next, head);

if(n != NULL)

n->next = front;

}

int main()

{

srand((unsigned)time(NULL));

node *LinkList;

CreateNode(LinkList);

PrintNode(LinkList);

LinkList = Reverse_1(LinkList);

// Reverse_2(LinkList, LinkList->next, *&LinkList);

PrintNode(LinkList);

putchar(10);

getchar();

return 0;

}

通过两个栈实现一个队列

参见博客:用两个栈实现队列

二分查找

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

void BinarySearch(int cc[], int num, int key)// 数组, 数组个数, 待查数字

{

int i = 0, j = num;

int cnt = 0, mid = 0;

while(i < j)

{

cnt++;

mid = (i + j) >> 1;

if(cc[mid] == key)

{

printf("%d %s, index: %d\n", cnt, cnt==1?"time":"times", mid);

return;

}

else if(cc[mid] < key)

i = mid;

else

j = mid;

}

}

int main()

{

int cc[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

BinarySearch(cc, 10, 3);

getchar();

return 0;

}

快速排序

两种略微有些不一样的快排(传入参数不同)

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

int cc[10];

void init()

{

srand((unsigned)time(NULL));

for(int i = 0; i < 10; i++)

{

int idx = rand()%10;

while(cc[idx])

idx = rand()%10;

cc[idx] = i+1;

}

}

void show()

{

for(int i = 0; i < 10; i++)

printf("%d ", cc[i]);

putchar(10);

}

void QuickSort_1(int cc[], int num)

{

int s = 0, t = num-1;

int base = cc[0];

if(num <= 1)

return;

while(s < t)

{

while(t > s && cc[t] >= base)

t--;

cc[s] = cc[t];

while(s < t && cc[s] <= base)

s++;

cc[t] = cc[s];

}

cc[s] = base;

QuickSort(cc, s);

QuickSort(cc+s+1, num-s-1);

}

void QuickSort_2(int cc[], int l, int r)

{

if(l >= r)

return;

int s = l, t = r;

int base = cc[l];

while(s < t)

{

while(t > s && cc[t] >= base)

t--;

cc[s] = cc[t];

while(s < t && cc[s] <= base)

s++;

cc[t] = cc[s];

}

cc[s] = base;

QuickSort_2(cc, l, s-1);

QuickSort_2(cc, s+1, r);

}

int main()

{

init();

show();

//QuickSort_1(cc, sizeof(cc)/sizeof(int));

QuickSort_2(cc, 0, sizeof(cc)/sizeof(int)-1);

show();

getchar();

return 0;

}

获得一个int型的数中二进制中的个数

没明白这个题目的意思,我们就理解成两个小题好了:

(1)求一个int型数字的二进制位数,如6->110->3位数

(2)求这个int型数字的二进制中'1'的个数

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

int main()

{

int num;

while(~scanf("%d", &num))

{

int bits = 0, cnt = 0;

int val = num;

while(val)

{

if(val & 1)

cnt++;

bits++;

val>>=1;

}

printf("%d has %d bit and %d '1' in binary\n", num, bits, cnt);

}

return 0;

}

输入一个数组,实现一个函数,让所有奇数都在偶数前面

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

int cc[10];

void init()

{

srand((unsigned)time(NULL));

for(int i = 0; i < 10; i++)

{

int idx = rand()%10;

while(cc[idx])

idx = rand()%10;

cc[idx] = i+1;

}

}

void show()

{

for(int i = 0; i < 10; i++)

printf("%d ", cc[i]);

putchar(10);

}

void Sort(int cc[], int size)

{

int s = 0, t = size-1;

while(s < t)

{

while(s < t && (cc[s]&1))

s++;

while(t > s && !(cc[t]&1))

t--;

cc[s] ^= cc[t];

cc[t] ^= cc[s];

cc[s] ^= cc[t];

}

}

int main()

{

init();

show();

Sort(cc, sizeof(cc)/sizeof(int));

show();

getchar();

return 0;

}

判断一个字符串是否是另一个字符串的子串

经典问题,用KMP算法。

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

char t[1000];

char p[100];

int f[100];

int cnt = 0;

void KMP() //需要使用的参数是char t[]长串, char p[]模式串.

{

int n = strlen(t);

int m = strlen(p);

/////计算模式串的失配边

f[0] = f[1] = 0;

for(int i = 1; i < m; i ++)

{

int j = f[i];

while(j && p[i] != p[j])j = f[j];

f[i+1] = p[i] == p[j]?j+1:0;

}

int j = 0;

for(int i = 0; i < n; i ++)

{

while(j && t[i] != p[j]) j = f[j];

if(p[j] == t[i])j ++;

if(j == m) //匹配成功

cnt ++;

}

}

int main()

{

cnt = 0;

gets(t);

gets(p);

KMP();

if(cnt >= 1)

printf("match!\n");

else

printf("not match!\n");

getchar();

return 0;

}

把一个int型数组中的数字拼成一个串,这个串代表的数字最小

关键就是要把int数组排个序,排序的cmp代码应该这样:如果两个数是A和B,那么应该比较AB和BA的大小,例如12、15,就要比较1215和1512的大小了。所以为了方便我们把int先转成char型,这样比较的时候直接strcat非常方便。

[cpp] view
plaincopyprint?

#include <iostream>

using namespace std;

void CreateArray(int *cc, int num)

{

srand((unsigned int)time(NULL));

for(int i = 0; i < num; i++)

cc[i] = rand() % 50;

}

int cmp(const void *a, const void *b)

{

char *s1 = new char[10];

char *s2 = new char[10];

strcpy(s1, *(char**)a);

strcat(s1, *(char**)b);

strcpy(s2, *(char**)b);

strcat(s2, *(char**)a);

return strcmp(s1, s2);

}

void ConvertToMinString(int *cc, int len)

{

char** str = (char**)new int[len];

for(int i = 0; i < len; i++)

{

str[i] = new char[5];

sprintf(str[i], "%d", cc[i]);

}

qsort(str, len, sizeof(char*), cmp);

for(int i = 0; i < len; i++)

printf("%s ", str[i]);

putchar(10);

}

int main()

{

int cc[5];

CreateArray(cc, 5);

ConvertToMinString(cc, 5);

getchar();

return 0;

}

输入一颗二叉树,输出它的镜像(每个节点的左右子节点交换位置)



用上递归和非递归两种方法。

[cpp] view
plaincopyprint?

#include <iostream>

#include <queue>

using namespace std;

struct node{

int val;

node *left;

node *right;

};

void insert(node *&root, int data)

{

if(root == NULL)

{

root = new node;

root->val = data;

root->left = root->right = NULL;

return;

}

if(root->val > data)

insert(root->left, data);

else

insert(root->right, data);

}

node* build()

{

node *root = NULL;

insert(root, 10);

for(int i = 8; i <= 12; i++)

{

if(i == 10)continue;

insert(root, i);

}

return root;

}

void showTree(node *root)

{

if(root == NULL) return;

printf("%d ", root->val);

showTree(root->left);

showTree(root->right);

}

void Mirror_1(node *&root) // 递归方法

{

if(root == NULL) return;

node *t = root->left;

root->left = root->right;

root->right = t;

Mirror_1(root->left);

Mirror_1(root->right);

}

void Mirror_2(node *&root) // 非递归方法

{

queue<node*> q;

if(root != NULL)

q.push(root);

while(!q.empty())

{

node *n = q.front();

q.pop();

node *t = n->left;

n->left = n->right;

n->right = t;

if(n->left != NULL)

q.push(n->left);

if(n->right != NULL)

q.push(n->right);

}

}

int main()

{

node *root = build();

showTree(root);putchar(10);

Mirror_1(root);

showTree(root);putchar(10);

Mirror_2(root);

showTree(root);putchar(10);

getchar();

return 0;

}

输入两个链表,找到它们第一个公共节点

也就是说这两个链表的形状就像“Y”一样。

我想到了两种办法:

①两个链表先分别枚举一遍,计算出两个链表的长度,假设是N和M,假设长链是N的长度,即N>=M,让长链先走N-M步,短链指针先不走,这样两个指针到结尾的距离都相同了,然后两个指针一边同步走一边进行比较,什么时候两个指针相同,当前节点就是第一个公共节点了。时间复杂度:O(n+m)

②设一个map或者其他键值对(哈希表),然后第一个链表走一步,根据其地址或主键建立索引,第二个链表走一步,根据其地址或主键建立索引,两个链表在遍历的时候分别去检索索引,什么时候发现已经记录了,那么当前节点就是第一个公共节点了。假设两个链表在相交之前的长度分别是N和M,则空间复杂度是O(max(n, m)*2),其时间复杂度是O(max(n, m) * 2)。

相比之下我认为②要好的多,毕竟时间相比于空间重要太多了。所以下面我给出了②的代码,用地址作为索引。其实我觉得如何创建这样交叉的链表和如何存储指针地址也可以作为一个题目哈。

[cpp] view
plaincopyprint?

#include <iostream>

#include <map>

using namespace std;

struct node{

int val;

node *next;

};

node* buildFirTree() // 第一个链表有20个节点

{

node *root = new node;

root->val = 1;

node *s = root, *t = root;

for(int i = 2; i <= 20; i++)

{

t = new node;

t->val = i;

s = s->next = t;

}

s->next = NULL;

return root;

}

node* buildSecTree(node *firnode)// 第二个链表创建5个结点,然后接到第一个链表的第8个结点上

{

node *root = new node;

root->val = 11;

node *s = root, *t = root;

for(int i = 2; i <= 5; i++)

{

t = new node;

t->val = 10 + i;

s = s->next = t;

}

node *k = firnode;

for(int i = 0; i < 7; i++)

k = k->next;

s->next = k;

return root;

}

void disp(node *root)

{

node *t = root;

while(t)

{

printf("%d ", t->val);

t = t->next;

}

putchar(10);

}

node *GetFirstCommonNode(node *fir, node *sec)

{

map<long, bool> mp;

mp.clear();

while(fir && sec)

{

if(mp[(long)fir] == true)

return fir;

mp[(long)fir] = true;

fir = fir->next;

if(mp[(long)sec] == true)

return sec;

mp[(long)sec] = true;

sec = sec->next;

}

return NULL;

}

int main()

{

node *fir = buildFirTree();

printf("First linklist: ");disp(fir);

node *sec = buildSecTree(fir);

printf("second linklist: ");disp(sec);

node *common = GetFirstCommonNode(fir, sec);

if(common != NULL)

printf("common node is: %d\n", common->val);

else

printf("There is no common node\n");

getchar();

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: