数据结构与算法(C++实现)

1.常见算法

1.1最基础的算法-swap(交换)

1.1.1 swap语法:

int main() {
	int a=1,b=10,temp;
	temp=a;
	a=b;
	b=temp;
	cout<<"a="<<a<<"  b="<<b<<endl;

	system("pause");
	return 0;
}

1.1.2 值传递方式(不成功):

void swap1(int x,int y);

int main() {
	int a,b;
	a=1;
	b=10;
	cout<<"一个不成功的swap方法"<<endl;
	cout<<"a="<<a<<"  b="<<b<<endl;

	swap1(a,b);//此处参数是按值传递的方式,将a和b各拷贝一个传递进去并进行交换
	           //所以发生变化的是拷贝的a和b,输出的a和b未发生改变
	cout<<"a="<<a<<"  b="<<b<<endl;

	system("pause");
	return 0;
}

void swap1(int x,int y)
{
	int temp;
	temp=x;
	x=y;
	y=temp;
}

输出:

一个不成功的swap方法
a=1  b=10
a=1  b=10

1.1.3 传指针方式

void swap1(int *x,int *y);

int main() {
	int a,b;
	a=1;
	b=10;
	cout<<"a="<<a<<"  b="<<b<<endl;
	
	swap1(&a,&b);//因为swap1函数的参数是指针,因此这里需要是地址传递
	cout<<"a="<<a<<"  b="<<b<<endl;

	system("pause");
	return 0;
}

void swap1(int *x,int *y)
{
	int temp;
	temp=*x;
	*x=*y;
	*y=temp;
}

输出:

a=1  b=10
a=10  b=1

1.1.4 引用的方式

void swap1(int &x,int &y);

int main() {
	int a,b;
	a=1;
	b=10;
	cout<<"a="<<a<<"  b="<<b<<endl;
	
	swap1(a,b);//因为引用就是别名,因此可以直接传递
	cout<<"a="<<a<<"  b="<<b<<endl;

	system("pause");
	return 0;
}

void swap1(int &x,int &y)
{
	int temp;
	temp=x;
	x=y;
	y=temp;
}

输出:

a=1  b=10
a=10  b=1

1.1.5 使用宏定义函数

各种类型都可以用,无论 int 或 double 等。

#define SWAP(x,y,t)((t)=(x),(x)=(y),(y)=(t))
int main() {
	int a,b,temp;
	a=1;
	b=10;
	cout<<"a="<<a<<"  b="<<b<<endl;
	
	SWAP(a,b,temp);
	cout<<"a="<<a<<"  b="<<b<<endl;

	system("pause");
	return 0;
}

输出:

a=1  b=10
a=10  b=1

1.1.6 使用std::swap函数(最简便)

各种类型都可以用,无论 int 或 double 等。

int main() {
	int a,b;
	a=1;
	b=10;
	cout<<"a="<<a<<"  b="<<b<<endl;
	
	std::swap(a,b);//C++内已经有这个函数,不用我们再自己写。直接调用即可
	cout<<"a="<<a<<"  b="<<b<<endl;

	system("pause");
	return 0;
}

输出:

a=1  b=10
a=10  b=1

1.2 排序算法

1.2.1 冒泡排序

思想:从左向右扫描数据,选择最大的数据,放在右边;

要点:比较相邻的两个数,如果左边的数大于右边的数,就进行交换。

法1

//函数声明
void bubblesort(int list[],int n); //list是一个数组,n代表数组元素的个数

int main() {
	int a[]={2,4,6,8,0,1,3,5,7,9};
	bubblesort(a,10);

	for(int k=0;k<10;k++)
	{
		cout<<a[k]<<"  ";
	}
	system("pause");
	return 0;
}

void bubblesort(int list[],int n) //函数定义
{
	for(int i=0;i<n-1;i++)
	{
			//如果有10个数据,则一共需要扫描9遍
			//每一遍扫描都是从list[0]开始,
				//第一遍扫描:从list[0]扫到list[9]
				//第二遍扫描:从list[0]到list[8];以此类推
		for(int j=0;j<n-i-1;j++)
		{
			if(list[j]>list[j+1])
				{
					std::swap(list[j],list[j+1]);
				};	
		}
	}
}

输出:

0  1  2  3  4  5  6  7  8  9  

法2

int main() {
	int arr[9]={4,2,8,0,5,7,1,3,9};  //1.创建数组
	cout<<"排序前:";
	for(int i=0;i<9;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl;
	
	//2.开始排序
	//总共排序轮数=元素个数-1
	for(int i=0;i<9-1;i++)
	{
		//内层循环对比次数=元素个数-当前轮数-1
		for(int j=0;j<9-i-1;j++)
		{
			if(arr[j]>arr[j+1])  //如果第一个数字比第二个数字大,则交换两个数字
			{
				int temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;
			}
		}
	}

	cout<<"排序后:";
	for(int i=0;i<9;i++)
	{
		cout<<arr[i]<<" ";
	}

	system("pause");
	return 0;
}

1.2.2 选择排序

从当前未排序的整数中找一个最小的整数,将它放在已排序的整数列表的后面。

要点:每次扫描只进行一次交换;选则一个最小的,放在左边。

void selectsort(int *a,const int n); //函数声明

int main() {
	int a[]={1,3,5,7,9,0,2,4,6,8};
	selectsort(a,10);
	for(int k=0;k<10;k++)
	{
		cout<<a[k]<<"  ";
	}
	system("pause");
	return 0;
}
void selectsort(int *list,const int n) //函数定义
{
	for(int i=0;i<n;i++)
	{
		int min=i;//把min看做一条毛巾,对数据做记号,暂定认为list[min]最小
		for(int j=i+1;j<n;j++)//第二遍扫描时,从第二个元素即list[1]开始
		{
			if(list[j]<list[min])
				{
					min=j;//扫描中发现list[j]比之前暂定的最小值还要小,就把最小值替换为list[j]
				}
		}
		swap(list[i],list[min]);
	}
}

1.2.3 插入排序

//设房间里有n个人,是无序状态,他们要依次到房间外进行有序排队

void insert( int *a,int n);
int main() {
	int x[]={2,4,6,8,0,1,3,5,7,9};
	insert(x,10);
	for(int i=0;i<10;++i)
	{
		cout<<x[i]<<"  ";
	}
	system("pause");
	return 0;
}

void insert( int *a,int n)
{
	int in,out;//out代表房间内未排队的人,in代表房间外已经排好队的人
	//开始时,out=0这个人已经出去了
	for(out=1;out<n;++out)
	{
		int temp=a[out];
		in=out;
		while(in>0 && a[in-1]>=temp)
		{
			a[in]=a[in-1];
			--in;
		}
		a[in]=temp;
	}
}

输出:

0  1  2  3  4  5  6  7  8  9

1.2.4 快速排序

最流行的排序算法、速度最快的排序算法;

运用递归思路。

1.2.5 归并排序

1.3 查找算法

1.3.1 顺序查找

没有排序的数据,只能进行顺序查找;

顺序查找速度较慢,二分查找速度比较快;

有排序的数据,可以进行顺序查找和二分查找。

//顺序查找

int sequent(int *a,const int n,const int x); //所要查找的数值是x
int main() {
	int m[]={1,3,5,7,9,0,2,4,6,8};
	int result;
	result=sequent(m,10,3);
	if(result==-1)
	{
		cout<<"没找到该数值"<<endl;
	}
	else
	{
		cout<<"所找数值在m["<<result<<"]里"<<endl;
	}
	system("pause");
	return 0;
}
int sequent(int *a,const int n,const int x) 
{
	int i;
	for( i=0;i<n;i++)
	{
		if(a[i]==x)
		{
		   return i;//如果找到x,则返回下标i
		}
	}
	if(i==n)  //如果没找到x,则返回-1
	{
		return -1;		
	}
}

1.3.2 折半查找(二分查找)

二分查找,速度比较快。

int binary(int *a,const int n,const int x); //用指针*a表示数组;n是数组元素个数;x是要查找的数据
int main() {
	int m[]={1,3,5,7,9,0,2,4,6,8};
	int result;
	result=binary(m,10,7);
	if(result==-1)
	{
		cout<<"没找到该数值"<<endl;
	}
	else
	{
		cout<<"所找数值在m["<<result<<"]里"<<endl;
	}
	system("pause");
	return 0;
}
int binary(int *a,const int n,const int x) 
{
	int low,high,mid;//分别表示最小的下标、最大的下标、下标中间值
	low=0; high=n-1;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(a[mid]==x)
		{
		  return mid;
		}
		else if(a[mid]<x)
		{
			low=mid+1;
		}
		else 
		{
			high=mid-1;
		}
	}
	return -1;
}

输出:

所找数值在m[3]

2.递归

递归,就是在运行的过程中调用自己。

一个简单例子:

void a()
{
	cout<<"hello"<<endl;
	a();//自己又调用了自己
}

int main() {
	a();
	system("pause");
	return 0;
}

输出:无限循环hello,陷入死循环
在这里插入图片描述

2.1 用递归计算阶乘

//5!= 5*4*3*2*1
//5! = 5*4!   4!=4*3!   3!=3*2!   2!=2*1!   1!=1*0!   0!=1
//n! = n*(n-1)!

long int JC(int n)
{
	if(n==0)
	{
		return 1;
	}
	else
	{
		return n*JC(n-1);
	}

}
int main() {
	cout<<JC(5)<<endl; //5的阶乘
	for(int num=0;num<10;num++) //0-9的阶乘
	{
	cout<<num<<"!="<<JC(num)<<endl;
	}
	system("pause");
	return 0;
}

输出:

120
0!=1
1!=1
2!=2
3!=6
4!=24
5!=120
6!=720
7!=5040
8!=40320
9!=362880

2.2 用迭代(循环)计算阶乘

long int JC(int n)
{
	long r=1;
	for(int i=n;i>0;i--)
	{
		r=r*i;
	}
	return r;
}
int main() {
	cout<<JC(5)<<endl; //5的阶乘
	for(int num=0;num<10;num++) //0-9的阶乘
	{
		cout<<num<<"!="<<JC(num)<<endl;
	}
	system("pause");
	return 0;
}

输出:同上

2.3 递归算法-折半查找

int binary(int *a,const int n,const int x); //迭代(循环)方式
int binary1(int *a,const int x,const int low,const int high);//递归方式

int main() {
	int m[]={1,3,5,7,9};
	int result;
	result=binary1(m,7,0,4);//递归方式
	if(result==-1)
	{
		cout<<"没找到该数值"<<endl;
	}
	else
	{
		cout<<"所找数值在m["<<result<<"]里"<<endl;
	}
	system("pause");
	return 0;
}

int binary(int *a,const int n,const int x) //迭代(循环)的方式
{
	int low,high,mid;//分别表示最小的下标、最大的下标、下标中间值
	low=0; high=n-1;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(a[mid]==x)
		{
		  return mid;
		}
		else if(a[mid]<x)
		{
			low=mid+1;
		}
		else 
		{
			high=mid-1;
		}
	}
	return -1;
}

int binary1(int *a,const int x,const int low,const int high)//递归方式
{
	if(low<=high)
	{
		int mid=(low+high)/2;
		if(x<a[mid])
		{
			return binary1(a,x,low,mid-1);
		}
		else if(x>a[mid])
		{
			return binary1(a,x,mid+1,high);
		}
		else
		{
			return mid;
		}
	}
	return -1;
}

输出:

所找数值在m[3]

2.4 递归算法-permutation(排列组合)

//对abc进行排列组合

void permutation( char *p,const int m,const int n)//m和n代表数组元素下标
{
	if(m==n)
	{
		for(int i=0;i<=n;i++)
		{
			cout<<p[i];
		}
		cout<<endl;
	}
	else
	{
		for(int i=m;i<=n;i++)
		{
			swap(p[m],p[i]);
			permutation(p,m+1,n);
			swap(p[m],p[i]);
		}
	}
	//swap(p[0],p[0]);
	//permutation(p,1,2);
	//swap(p[0],p[0]);//以a开头,后面跟着bc的所有排列

	//swap(p[0],p[1]);
	//permutation(p,1,2);
	//swap(p[0],p[1]);//以b开头,后面跟着ac的所有排列

	//swap(p[0],p[2]);
	//permutation(p,1,2);
	//swap(p[0],p[2]);//以c开头,后面跟着ab的所有排列
}

int main() {
	char s[]="abc";
	permutation(s,0,2);
	
	system("pause");
	return 0;
}

在这里插入图片描述
输出:

abc
acb
bac
bca
cba
cab

3.栈和队列

3.1 栈

3.2 队列

4.链表

4.1链表基础知识

  • 数组是最常用的数据结构,但存在缺点。例如在一个有序数组中插入新数据或删除某数据时,将会使很多数据发生移动,导致效率降低。
  • 链表是第二常用的数据结构。
  • 链表中插入或删除一个数据,只需要修改该数据相邻数据的指针指向即可,不需要移动其他数据的位置。
    在这里插入图片描述
  • 链表就是表头指针和一串相继链接的结点的总称。
  • 链表每个节点都包含数据域和指针域。
  • 首指针(表头指针) :指向链表的第一个结点的指针变量。 其值为首结点的存储地址。.
  • 表尾结点(最后一个结点)的链域值为空(NULL)
    在这里插入图片描述

4.2 链表的插入操作

4.2.1 指定位置的插入

插在表头:如图,把陈插到表头
在这里插入图片描述

p->next=head;  //先把陈与张连接,使结点张作为结点陈的后继节点
head=p;            //修改表头指针head,使其指向新的头结点陈

插在表中:如图,把陈插到王和李之间

在这里插入图片描述

p->next=q->next;   //先把陈与李连接
q->next=p;         //再把王与陈连接

4.2.2 指定位置的删除

删除表头结点

在这里插入图片描述

q=head;               //为了回收空间,先用q指针记住表头张
head=head->next;      //修改head,使其指向新的表头结点
free(q);              //将空间回归

删除表中结点:删除结点王
在这里插入图片描述

p=q->next;          //先用p指针记住结点李
//此时结点赵的地址是p->next,也是q->next->next
q->next=p->next;    //将结点王的后继结点修改为结点赵,即删除了结点李   
free(p);            //将空间回收           

链表的特点

  • 结点地址不连续
  • 插入/删除不移动结点,耗时为O(1)
  • 用于动态管理。

4.3链表的构造

构造链表的通用算法

  1. 构造“空链表”
  2. 读入第一个元素值。
  3. 当读入的元素值不是“输入结束标记”时,循环执行步骤4~7。
  4. 申请一个新结点。
  5. 将读入的元值存入新结点的值域。
  6. 将新结点“插在”链表中。
  7. 读入“下一个”元素值,转步骤3。
  8. 构造完毕,返回首指针。
内含资源如下: 1.基本数据结构 1.1.Array ........... 动态数组 1.2.LinkedList ... 链表 1.3.BST .............. 二分搜索树 1.4.MapBST ..... 二分搜索树(用于实现映射) 1.5.AVLTree ...... AVL树 2.接口 2.1.Queue ........... 队列接口 2.2.Stack .............. 栈接口 2.3.Set .................. 集合接口 2.4.Map ............... 映射接口 2.5.Merger .......... 自定义函数接口 2.6.UnionFind ..... 并查集接口 3.高级数据结构 3.1.ArrayQueue .......................... 队列_基于动态数组实现 3.2.LinkedListQueue .................. 队列__基于链表实现 3.3.LoopQueue ........................... 循环队列_基于动态数组实现 3.4.PriorityQueue ....................... 优先队列_基于最大二叉堆实现 3.5.ArrayPriorityQueue ............. 优先队列_基于动态数组实现 3.6.LinkedListPriorityQueue ..... 优先队列_基于链表实现 3.7.ArrayStack ............................. 栈_基于动态数组实现 3.8.LinkedListStack ..................... 栈_基于链表实现 3.9.BSTSet ..................................... 集合_基于二分搜索树实现 3.10.LinkedListSet ....................... 集合_基于链表实现 3.11.BSTMap ................................ 映射_基于二分搜索树实现 3.12.AVLTreeMap ....................... 映射_ 基于AVL树实现 3.13.LinkedListMap .................... 映射_基于链表实现 3.14.MaxHeap ............................. 最大二叉堆 3.15.SegmentTree ...................... 线段树 3.16.Trie ......................................... 字典树 3.17.QuickFind ............................ 并查集_基于数组实现 3.18.QuickUnion ......................... 并查集_基于树思想实现
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值