首页 > 编程语言 >数据结构与算法(长期更新)

数据结构与算法(长期更新)

时间:2023-02-13 22:47:20浏览次数:58  
标签:int 二维 更新 队列 算法 数组 front 数据结构 rear

前言

该篇为我跟着006_尚硅谷_线性结构和非线性结构_哔哩哔哩_bilibili视频学习时所做的笔记,内容属于入门级别,更加深入的研究内容我以后会单独写博客

1.线性结构与非线性结构

  • 线性结构
    • 特点是数据元素存在一对一的线性关系
    • 有两种存储结构:顺序存储结
    • 构(数组)与链式存储结构(链表)。
      • 顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的(地址是连续的)
      • 链式存储的线性表称为链表,存储元素的地址不一定连续。我们可以借此充分利用零碎的内存,元素节点中存放数据元素以及相邻元素的地址信息
    • 常见的有:数组、队列、链表、栈
  • 非线性结构
    • 常见的有:二维数组、多维数组、广义表、树结构、图结构

2. 稀释数组

用来压缩一个特殊二维数组的方式,这个二维数组的绝大大部分元素为一个相同的数(通常为0),而少部分元素的值为其他值。最经典的就是五子棋程序,空位置为0,黑子为1,白子为2,如果用正常数组来记录,其实空位置是没有意义的数据(他们都是默认值),很占用内存

我们通过稀疏数组来记录原二维数组中这些特殊值的位置,其他位置的值相同所以可以不用记录

第一行来记录整个二维数组的行列以及特殊元素个数,而从数组第一位开始挨个记录特殊元素的行、列、值

image-20230209105633787

二维数组转稀疏数组

  1. 遍历原始二维数组,得到有效数据个数sum
  2. 根据sum创建稀疏数组,我们一般命名为sparseArr,大小为[sum+1][3](第零行用来记录二维数组信息)
  3. 将二维数组有效数据存入稀疏数组中

稀疏数组转二维数组

  1. 先读取稀疏数组第一行来创建二维数组
  2. 读取后几行,恢复特殊元素

程序

我由于想把所有步骤都搞成函数,所以用了好多我不熟练的指示点(比如指针),所以反而是程序更复杂了,但是中间我也学到了很多

#include<bits/stdc++.h>

using namespace std;

//填充二维数组的内容,包括默认值和特殊值
void makeArray(int *a,int row,int col){
	for(int i=0;i<row;i++){
		for(int j=0;j<col;j++){
			a[i*col+j]=0;
		}
	}	
	a[1*col+2]=1;
	a[2*col+3]=2;
	return;
}

//打印二维数组
void printArray(int *a,int row,int col){
	for(int i=0;i<row;i++){
		for(int j=0;j<col;j++){
			printf("%2d ",a[i*col+j]);
		}
		cout<<endl;
	}	
	cout<<"-------------------------------------------"<<endl;
	return;
}

//生成稀疏数组
int * makeSparseArray(int *a,int row,int col){
	int num=0;
	for(int i=0;i<row;i++){
		for(int j=0;j<col;j++){
			if(a[i*col+j]!=0) num++;
		}
	}
	//动态管理内存,防止系统收回局部变量
	int * ptr=new int[(num+1)*3];
	int line=1;
	ptr[0]=row;
	ptr[1]=col;
	ptr[2]=num;
	for(int i=0;i<row;i++){
		for(int j=0;j<col;j++){
			if(a[i*col+j]!=0){
				ptr[line*3]=i;
				ptr[line*3+1]=j;
				ptr[line*3+2]=a[i*col+j];
				line++;
			}
		}
	}
	return ptr;	
}

//将稀疏数组还原为二维数组
int * resume(int *a,int row,int col){
	//读取二维数组的行数与列数
	int r_row=a[0];
	int r_col=a[0];
	//同理
	int * ptr=new int [r_row*r_col];
	//初始化二维数组默认值
	for(int i=0;i<r_row;i++){
		for(int j=0;j<r_col;j++){
			ptr[i*r_col+j]=0;
		}
	}
	for(int i=1;i<=a[2];i++){
		//读取该特殊元素的坐标与值
		int this_row=a[i*3];
		int this_col=a[i*3+1];
		int value=a[i*3+2];
		ptr[this_row*r_col+this_col]=value;
	}
	return ptr;
}

int main(){
	int array[11][11];
	//得到二维数组的行数与列数,这里是为了提高程序扩展性,其实就是11和11
	int row=sizeof(array)/sizeof(array[0]);
	int col=sizeof(array[0])/sizeof(array[0][0]);
	makeArray(*array,row,col);
	printArray(*array,row,col);
	int * sparseArray=makeSparseArray(*array,row,col);
	printArray(sparseArray,sparseArray[2]+1,3);
	int * resumeArray=resume(sparseArray,sparseArray[2]+1,3);
	printArray(resumeArray,sparseArray[0],sparseArray[1]);
	//删除动态内存,防止发生内存泄露
	delete[] sparseArray;
	delete[] resumeArray;
	return 0;
}

3.队列

比较经典的例子就是银行排队与叫号

  • 队列是一个有序列表,可以用数组或者链表来表示
  • 先入先出

我们看下面的示意图

image-20230212182139743

  1. 图中有我们的容器,从0开始,所以最大位置为MaxSize-1,rear用来记录增加,front用来记录结束
  2. 当有数据进入我们的队列时,front不动,rear开始变化,变红的部分代表进入队列的数据(相当于当前银行前台开始接客)
  3. 当数据处理结束时,rear不动,front开始从移动,front是慢于rear的,这也符合我们先进先出的要求,图中1、2数据处理结束

数组模拟队列

有缺陷的非环形队列

目前数组只能使用一次,不能复用。数组rear指针指到最大位置后这个队列也就再也不能存数据了

#include<bits/stdc++.h>

using namespace std;

class ArrayQueue{
	public:
		int maxSize;
		int front;
		int rear;
		int *arr;
	public:
		void init(int arrMaxSize);
		bool isEmpty();
		bool isFull();
		void addQueue(int n);
		int getQueue();
		void showQueue();
		int headQueue();
	};
	void ArrayQueue::init(int arrMaxSize){
			maxSize=arrMaxSize;
			arr=new int [maxSize];
			front=-1;
			rear=-1;
			for(int i=0;i<maxSize;i++){
				arr[i]=0;
			}
	}
	bool ArrayQueue::isEmpty(){
		return rear==front;
	}
	bool ArrayQueue::isFull(){
		return rear==maxSize-1;
	}
	void ArrayQueue::addQueue(int n){
		if(isFull()){
			cout<<"队列满,不能添加数据"<<endl;
			return;
		}
		rear++;
		arr[rear]=n;
	}
	int ArrayQueue::getQueue(){
		if(isEmpty()){
			cout<<"队列空,不能取数据"<<endl;
			return 0;
		}
		int res;
		front++;
		res=arr[front];
		arr[front]=0;
		return res;
	}
	void ArrayQueue::showQueue(){
		if(isEmpty()){
			cout<<"队列为空,没有数据可以展示"<<endl;
			return;
		}
		cout<<"=================="<<endl;
		for(int i=0;i<maxSize;i++){
			printf("arr[%d]=%d\n",i,arr[i]);
		}
		cout<<"==================";
	}
	int ArrayQueue::headQueue(){
		if(isEmpty()){
			cout<<"队列为空,没有数据"<<endl;
			return 0;
		}
		return arr[front+1];
	}

int main(){
	cout<<"请输入队列最大尺寸:";
	int max;
	cin>>max;
	ArrayQueue a;
	a.init(max);
	char key=' ';
	bool loop=true;
	while(loop){
		cout<<"s(show):显示队列"<<endl;
		cout<<"a(add):添加数据到队列"<<endl;
		cout<<"g(get):从队列中取出数据"<<endl;
		cout<<"h(head):查看队列头的数据"<<endl;
		cout<<"e(exit):退出程序"<<endl;
		cin>>key;
		int res;
		switch(key){
			case 's':
				a.showQueue();
				break;
			case 'e':
				loop=false;
				break;
			case 'a':
				cout<<"请输入一个数字";
				int value;
				cin>>value;
				a.addQueue(value);
				break;
			case 'g':
				res=a.getQueue();
				cout<<"取出的数据为"<<res<<endl; 
				break;
			case 'h':
				res=a.headQueue();
				cout<<"队列头的数据是"<<res<<endl; 
				break;
		}
	system("pause");
	system("cls");
	}
	return 0;
}

环形队列

我们做如下修改

  1. front变量的含义做一个调整:front指向队列的第一个元素,也就是说arr[front]代表的就是队列中当前最早的那个元素,front的初始值=0
  2. rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值=0
  3. 当队列满时,条件是(rear+1)%maxSize=front
  4. 当队列为空时,rear=front
  5. 当我们这样分析时,队列中有效的数据的个数是(rear+maxSize-front)%maxSize

标签:int,二维,更新,队列,算法,数组,front,数据结构,rear
From: https://www.cnblogs.com/zaughtercode/p/17118109.html

相关文章