1.排序算法
1.1暴力的解决方法,冒泡排序,时间复杂度为O(n2)
1.2快速排序,时间复杂度为O(n log n)
void quick_sort(int v[],int left,int right){
if(left<right)
{
int l=left,r=right,x=v[l];
while(l<r)
{
while(l<r && v[r]>=x )//从右向左找小于x的数
r–;
if(l<r)
v[l++]=v[r];
while(l<r && v[l]<x)//从左到右找大于等于x的数
l++;
if(l<r)
v[r--]=v[l];
}
v[l]=x;
quick_sort(v,left,l-1);//递归调用
quick_sort(v,l+1,right);
}
}
1.3归并排序,时间复杂度为O(n log n)
/该函数将数组下标范围[l1,r1]和[l2,r2]的有序序列合并成一个有序序列/
void merge(vector& nums, int l1, int r1, int l2, int r2 ) {
int i = l1; //左半部分起始位置
int j = l2; //右半部分起始位置
int n = (r1 - l1 + 1) + (r2 - l2 + 1); //要合并的元素个数
vector temp(n); //辅助数组
int k = 0; //辅助数组其起始位置
while (i <= r1&&j <= r2) { //挑选两部分中最小的元素放入辅助数组中
if (nums[i] < nums[j])
temp[k++] = nums[i++];
else
temp[k++] = nums[j++];
}
//如果还有剩余,直接放入到辅助数组中
while (i <= r1)
temp[k++] = nums[i++];
while (j <= r2)
temp[k++] = nums[j++];
//更新原始数组元素
for (int i = 0; i < n;i++)
{
nums[l1 + i] = temp[i];
}
}
/二路归并排序(递归实现)/
void MergeSort(vector& nums,int start, int end) {
if (start < end) {
int mid = (start + end) >> 1; //分割序列
MergeSort(nums, start, mid); //对序列左半部分进行规并排序
MergeSort(nums, mid + 1, end); //对序列右半部分进行规并排序
merge(nums, start, mid, mid + 1, end); //合并已经有序的两个序列
}
}
1.4堆排序,时间复杂度为O(n log n)
void maxHeapDown(int* a, int start, int end)
{
int c = start; // 当前(current)节点的位置
int l = 2c + 1; // 左(left)孩子的位置
int tmp = a[c]; // 当前(current)节点的大小
for (; l <= end; c=l,l=2l+1)
{
// "l"是左孩子,"l+1"是右孩子
if ( l < end && a[l] < a[l+1])
l++; // 左右两孩子中选择较大者,即m_heap[l+1]
if (tmp >= a[l])
break; // 调整结束
else // 交换值
{
a[c] = a[l];
a[l]= tmp;
}
}
}
/*
- 堆排序(从小到大)
- 参数说明:
-
a -- 待排序的数组
-
n -- 数组的长度
/
void heapSortAsc(int a, int n)
{
int i,tmp;
// 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
for (i = n / 2 - 1; i >= 0; i--)
maxHeapDown(a, i, n-1);
// 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
for (i = n - 1; i > 0; i--)
{
// 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
tmp = a[0];
a[0] = a[i];
a[i] = tmp;
// 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
// 即,保证a[i-1]是a[0...i-1]中的最大值。
maxHeapDown(a, 0, i-1);
}
}
2.括号匹配问题,用栈解决
括号匹配(1)
算法:使用栈类型,当遇到左括号时,入栈;当遇到右括号时,判断栈是否为空以及栈顶元素与该右括号是否匹配,若匹配,则出栈,否则,返回错误信息。
括号匹配(2)
算法:算法的使用与括号匹配(1)一样,只是加了一个判断。先计算字符串中左右括号各自的数量,进行比较,若左括号多,则返回error2;若右括号多,则返回error3;若左右括号一样多,则进行括号匹配(1)中的步骤。
括号匹配(3)
算法:先进行error1和error3的判别:当遇到左括号时入栈;当遇到右括号时,若栈为空,则返回error3;若栈不为空,但栈顶元素与该右括号不匹配,则返回error1.再进行error的判别:这里使用了变形,我从字符串的最后面往前读取,当遇到右括号时入栈;当遇到左括号时,若栈为空,则返回error2。
3.最短路径问题
3.1 Dijkstra算法,求有向图G的某顶点到其余节点的最短路径pre以及长度dist
#include
using namespace std;
int matrix[100][100];//邻接矩阵
bool visited[100];//标记数组
int dist[100];//原点到i顶点的最短距离
int pre[100];//记录最短路径。pre[i]放的是i的前驱节点
int source;//源节点
int vertex_num;//顶点数
int edge_num;//边数
void Dijkstra(int source)
{
//首先初始化
//memset(visited,0,sizeof(visited));
visited[source] = true;
for (int i = 0; i < vertex_num; i++)
{
dist[i] = matrix[source][i];
pre[i] = source;
}
int min_cost;//最短距离
int min_cost_index;//权值最小的那个顶点的下标。(求好了)
//主循环
for (int i = 1; i < vertex_num; i++)
{
min_cost = INT_MAX;
for (int j = 0; j < vertex_num; j++)
{
//注意要确保这个点没有找过。
if (visited[j]==false&&dist[j] < min_cost)
{
min_cost_index = j;
min_cost = dist[j];
}
}
visited[min_cost_index] = true;//找到某一个点的最短距离
//利用该点进行dist的更新,并且调整前驱。
for (int j = 0; j < vertex_num; j++)
{
//确保有连接
if (visited[j] == false && matrix[min_cost_index][j] != INT_MAX&&min_cost+ matrix[min_cost_index][j] < dist[j])
{
dist[j] = min_cost + matrix[min_cost_index][j];
pre[j] = min_cost_index;
}
}
}
}
int main()
{
cout << “请输入图的顶点数(<100):”;
cin >> vertex_num;
cout << "请输出图的边数: ";
cin >> edge_num;
for (int i = 0; i < vertex_num; i++)
{
for (int j = 0; j < vertex_num; j++)
{
matrix[i][j] = (i != j) ? INT_MAX : 0;
}
}
cout << “请输入边的信息:\n”;
int u, v, w;
for (int i = 0; i < edge_num; i++)
{
cin >> u >> v >> w;
matrix[u][v] = matrix[v][u] = w;
}
cout << "请输入源点(<" << vertex_num << "): ";
cin >> source;
Dijkstra(source);
for (int i = 0; i < vertex_num; i++)
{
if (i != source)
{
//路径是反的,从目标点向前不断找前驱的过程。
cout << source << "到" << i << "最短距离: " << dist[i] << ",路径是:" << i;
int t = pre[i];
while (t != source)
{
cout << "--" << t;
t = pre[t];
}
cout << "--" << source << endl;
}
}
return 0;
}
3.2 从一个矩阵的右上角走到左下角的最短路径
4.迷宫问题,深度优先搜索/广度优先搜索
#include
#include
using namespace std;
int num;//迷宫的长和宽,这里的迷宫都是正方形
int maze[10][10];//迷宫
int vis[10][10];//记录迷宫中的某个位置是否访问过
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//四个方向,right,left,down,up
int s_x,s_y;//起点的坐标
int e_x,e_y;//终点的坐标
struct point //位置
{
int x,y;
int d;//0-right,1-left,2-down,3-up
}p;
stack path,temp;//记录路径,temp是临时变量
stack rode,rode1;
int count=0;
int flag[10][100];
int row=0,col;
void dfs(int x,int y)//x,y是当前位置
{
if(xe_x && ye_y)//找到终点
{
count=1;//判断是否能找到终点
col=1;
int counter=0;//计算每一条路径的步数
//cout<<“2”<<endl;
//cout << “******************路径”<< ++count << “******************” << endl;
while(!path.empty())//将path里面的点取出来,放在temp里面
{//path从栈顶-栈底的方向,路径是从终点-起点的顺序
point p1 = path.top();
path.pop();
temp.push(p1);
}
while(!temp.empty())
{//输出temp里面的路径,这样刚好是从起点到终点的顺序
point p1 = temp.top();
temp.pop();
path.push(p1);//将路径放回path里面,因为后面还要回溯!!!
flag[row][col++]=p1.d;
counter++;
//cout << “(” << p1.x << “,” << p1.y << ") ";
/if(p1.d0) cout<<“RIGHT”<<endl;
else if(p1.d1)cout<<“LEFT”<<endl;
else if(p1.d2)cout<<“DOWN”<<endl;
else if(p1.d3)cout<<“UP”<<endl;/
}
flag[row][0]=counter;//每一行的第一个数用来存储路径步数
row++;
return;
}
if(x<0 || x>=num || y<0 || y>=num)//越界
return;
//以下是还没找到终点且没有出界的
for(int i=0;i<4;i++)//从四个方向探测
{
//选择一个方向,前进一步之后的新坐标nx,ny
int nx=x+dir[i][0];
int ny=y+dir[i][1];
//cout<<"("<<nx<<","<<ny<<")1";cout<<endl;
if(0<=nx&&nx<num && 0<=ny&&ny<num && (maze[nx][ny]==1||maze[nx][ny]==3)&&vis[nx][ny]==1)
//迷宫中,可行的点数值为1,而终点也是可行的,但是终点的值为3,所以需要用或来判断
//nx,ny没有越界,迷宫该点可走,记录点表示没有走过
{
vis[nx][ny]=0;//设为访问过
p.x=nx;
p.y=ny;
p.d=i;
path.push(p);//当前的位置进栈
dfs(nx,ny);//进一步探测
vis[nx][ny]=1;//回溯
path.pop();//因为是回溯,所以需要出栈
}
}
}
int main()
{
cin>>num; //输入迷宫的长宽
//输入迷宫以及将记录数组初始化为1
for(int i=0;i<num;i++)
for(int j=0;j<num;j++)
{
vis[i][j]=1;
cin>>maze[i][j];
}
//找到迷宫的起点和终点
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
if(maze[i][j]==2)
{
s_x=i;s_y=j;
}
else if(maze[i][j]==3)
{
e_x=i;e_y=j;
}
else
continue;
}
}
//cout<<"("<<s_x<<","<<s_y<<") “;
//cout<<”("<<e_x<<","<<e_y<<") ";
p.x=s_x;
p.y=s_y;
p.d=10;
path.push§;//起点入栈
dfs(s_x,s_y) ;
if(count==0)
cout<<"NO"<<endl;
else
{
int min=101,k;
for(int i=0;i<row;i++)//找到步数最少的那一条路径
{
if(flag[i][0]<min)
{
min=flag[i][0];
k=i;
}
}
for(int j=1;j<=flag[k][0];j++)
{
if(flag[k][j]==0) cout<<"RIGHT"<<endl;
else if(flag[k][j]==1) cout<<"LEFT"<<endl;
else if(flag[k][j]==2) cout<<"DOWN"<<endl;
else if(flag[k][j]==3) cout<<"UP"<<endl;
}
}
return 0;
}
5.N皇后问题
回溯算法基本的步骤思想为:
1)从第一行开始
2 )如果所有的皇后已经放置完成, 生成解,并且返回 true
3)尝试当前行的所有列,如果当前行与列是合法的
3.1 修改棋盘让其成为部分解,
3.2 然后递归查看(主要是 2, 3,4)该解是否合法
3.3 Backtrack 棋盘进行回溯
4) 如果上述所有的组合都为非法,返回 false
void check_m(int num) //N皇后程序
{
int n = 0;
int i = 0, j = 0;
while (i < num)
{
while (j < num) //对i行的每一列进行探测,看是否可以放置皇后
{
if(valid(i, j)) //该位置可以放置皇后
{
a[i] = j; //第i行放置皇后
j = 0; //第i行放置皇后以后,需要继续探测下一行的皇后位置,
//所以此处将j清零,从下一行的第0列开始逐列探测
break;
}
else
{
++j; //继续探测下一列
}
}
if(a[i] == INITIAL) //第i行没有找到可以放置皇后的位置
{
if (i == 0) //回溯到第一行,仍然无法找到可以放置皇后的位置,
//则说明已经找到所有的解,程序终止
break;
else //没有找到可以放置皇后的列,此时就应该回溯
{
–i;
j = a[i] + 1; //把上一行皇后的位置往后移一列
a[i] = INITIAL; //把上一行皇后的位置清除,重新探测
continue;
}
}
if (i == num - 1) //最后一行找到了一个皇后位置,
//说明找到一个结果,打印出来
{
printf("第[%d]种方法: ",++n);
//printf(“answer %d : \n”, ++n);
print(num);
//不能在此处结束程序,因为我们要找的是N皇后问题的所有解,
//此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。
j = a[i] + 1; //从最后一行放置皇后列数的下一列继续探测
a[i] = INITIAL; //清除最后一行的皇后位置
continue;
}
++i; //继续探测下一行的皇后位置
}
}
6.栈的实现(使用数组)
bool myStack::empty() const // 栈空则返回true
{
if(_size0)
return true;
else
return false;
}
int myStack::top() const // 返回栈顶元素,如果栈为空则返回0
{
if(empty())
return 0;
else
{
return mtop->number;
}
}
bool myStack::pop()
{
if(empty())
return false;
else
{
Node * mtop2=mtop;
mtop=mtop->next;
delete mtop2;
mtop2=NULL;
_size–;
return true;
}
}
bool myStack::push(int _number) // 请注意push失败的情况,即new失败
{
if(mtopNULL)
{
mtop=new Node;
if(mtopNULL)
return false;
else
{
mtop->next=NULL;
mtop->number=_number;
_size++;
return true;
}
}
else
{
Node *mtop2=new Node;
if(mtop2NULL)
return false;
else
{
mtop2->number=_number;
mtop2->next=mtop;
mtop=mtop2;
_size++;
return true;
}
}
}
int myStack::size() const
{
return _size;
}
myStack& myStack::operator=(const myStack& stack)
{
if(mtop!=NULL)
{
Nodemtop3=mtop;
while(mtop3!=NULL)
{
Nodemtop4=mtop3;
mtop3=mtop4->next;
delete mtop4;
}
mtop=NULL;
this->_size=0;
}
else
{
if(stack._size==0)
return this;
else
{
_size=stack._size;
mtop=new Node;
mtop->number=stack.mtop->number;
Nodemtop2=stack.mtop->next;
Node*mtop1=mtop;
while(mtop2!=NULL)
{
mtop1->next=new Node;
mtop1=mtop1->next;
mtop1->number=mtop2->number;
mtop2=mtop2->next;
}
mtop1->next=NULL;
return *this;
}
}
}
7.队列的实现
void queue::push(E a)
{
if(isFull())
return ;
else
{
rear++;
storage[rear]=a;
max_size++;
}
}
void queue::pop()
{
if(isEmpty())
return ;
else
{
max_size–;
head–;
if(max_size0)
{
head=0;
rear=-1;
}
}
}
E queue::front()
{
if(isEmpty())
return 0;
else
return storage[head];
}
E queue::back()
{
if(isEmpty())
return 0;
else
return storage[rear];
}
bool queue::isFull()
{
if(max_size10)
return true;
else
return false;
}
bool queue::isEmpty()
{
if(max_size==0)
return true;
else
return false;
}
void queue::clear()
{
max_size=0;
head=0;
rear=-1;
}
以上就是一些项目和经典的例子。还有挺多是上课时的作业,这里就不一一列举了。