数据结构~栈,队列,顺序表,哈希

目录

链式栈:

数组栈:

寻路问题:

队列:

 线性结构:顺序表:

哈希结构:


栈结构:

FILO  先进后出,后来居上的一种存储方式

栈的基本属性:栈内存 ,栈顶标记,栈的当前元素个数

栈的基本操作:入栈,出栈,获取栈顶元素:栈顶标记的元素(头插法)

万金油操作:判断是否为NULL,当前栈中数据个数

根据实现方式,栈分为两种方式:链式栈数组栈

队列:FIFO 先进先出,排队的方式(尾插法)

链式栈:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//链表结构
struct Node
{
	int data;
	struct Node* next;
};

struct Node* creatNode(int data)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	newNode->next = NULL;
	newNode->data = data;
	return newNode;
}
//栈结构
struct stack
{
	int sizeStack;//栈当前元素个数
	struct Node* stackTop;//栈顶标记用指针表示
};
//创建栈,描述栈的最初状态
struct stack* createStack()
{
	struct stack* pstack = (struct stack*)malloc(sizeof(struct stack));
	pstack->sizeStack = 0;
	pstack->stackTop = NULL;
	return pstack;
}
//万金油函数
int size(struct stack* pstack)
{
	return pstack->sizeStack;
}
int empty(struct stack* pstack)
{
	return pstack->sizeStack!=0;
}
//入栈操作--》链表的头插法,无头链表 栈顶指针永远指向第一个节点
void push(struct stack* pstack, int data)
{
	struct Node* newNode = creatNode(data);
	if (newNode == NULL)
	{
		return;
	}
	else
	{
		newNode->next = pstack->stackTop;
		pstack->stackTop = newNode;
		pstack->sizeStack++;
	}
}
//出栈:链表的删除:无头链表的头删法
void pop(struct stack* pstack)
{
	if (pstack->sizeStack == 0)
	{
		printf("栈为空,无法删除");
		return;
	}
	else
	{
		//堆内存实现的栈需内存释放
		struct Node* nextNode = pstack->stackTop->next;
		free(pstack->stackTop);
		pstack->stackTop = nextNode;
		pstack->sizeStack--;
	}
}
//获取栈顶元素
int top(struct stack* pstack)
{
	if (pstack->sizeStack == 0)
	{
		printf("栈为空,无法获取栈顶元素");
		return 0;
	}
	return pstack->stackTop->data;
}

int main()
{
	struct stack* mystack = createStack();
	int num = 1234;
	while (num != 0)
	{
		push(mystack, num % 2);
		num /= 2;
	}
	
	while (empty(mystack))
	{
		printf("%d", top(mystack));//栈顶元素先出
		pop(mystack);
	}

	return 0;
}

数组栈:

方便,但是数组长度受限制,是自己申请的才要释放,不是自己的系统会自动回收!

int main()
{
	//struct stack* mystack = createStack();
	int num = 1234;
	//通常情况用数组充当栈内存
	int stack[20];
	int stackTop = -1;//下标充当位置
	while (num != 0)
	{
		//入栈操作
		stackTop++;
		stack[stackTop] = num % 2;//等同于stack[++stackTop] = num % 2;
		num /= 2;
	}
	//因为栈顶标记正好是等于数组下标
	while (stackTop != -1)
	{
		printf("%d ", stack[stackTop]);//获取栈顶元素
		//出栈,伪删除
		stackTop--;
	}
	return 0;
}

寻路问题:

迷宫寻路

补充: 


#include <stdio.h>

//指针传参的两种方式
void print(int arr[],int a){}
void print2(int* arr,int a){}

int main()
{
	int arr[3] = { 1,2,3 };
	print(arr, 4);
	print2(arr, 4);
	return 0;
}

 二级指针申请一段内存存放多个一级指针存放整数

int** makeArray(int row, int cols)
{
	int** array = (int**)malloc(sizeof(int) * row);
	for (int i = 0; i < cols; i++)
	{
		array[i] = (int*)malloc(sizeof(int) * cols);
	}
	return array;
}

 走迷宫流程:

默认从(1,1)开始走,默认方向是往右(0)走,准备往右走时先提前计算出往右走后落点处坐标,也就是(1,2),然后通过判断(1,2)是不是墙(判断是否为0),如果是墙就换个方向测试直到下一个落脚点不是墙,如果4个方向都是墙那就直接退出外循环,现在当测到往下的方向(1)时可以走那就退出内循环然后把当前位置(1,1)入栈,再把下一个落脚点的坐标变成当前位置,也就是新的当前位置是(2,1),然后再把上一个落脚点堵住(置1),然后把方向改回默认方向(0),回到判断下一个是否为落脚点的语句里,像之前那样个个方向都判断,直到下一个落脚点不是墙为止,判断过后可以发现下一个落脚点就是(2,2),所以故技重施,把当前位置(2,1)入栈,再把下一个落脚点的坐标变成当前位置,也就是新的当前位置是(2,2),再把上一个落脚点堵住(置1),然后方向也改回默认方向,重复上面步骤,然后判断过后可以发现下一个落脚点就是(2,3),所以故技重施,把当前位置(2,2)入栈,再把下一个落脚点的坐标变成当前位置,也就是新的当前位置是(2,3),然后继续当到出口时把(2,3)入栈,然后此时坐标是(3,3)已经是地图的右下角故不满足循环条件退出循环把(3,3)入栈。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define R 3//出口
#define C 3

//数组里面去寻路:位置- ->行和列
struct position
{
	int row;//行
	int cols;//列
};
struct position pathStack[100];//存放路径-->栈内存
int stackTop = -1;//栈顶标记
int** maze = NULL;//二维数组去描述地图
int size = 0;//迷宫大小
int** makeArray(int row, int cols)
{
	int** array = (int**)malloc(sizeof(int) * row);
	for (int i = 0; i < cols; i++)
	{
		array[i] = (int*)malloc(sizeof(int) * cols);
	}
	return array;
}
//用户输入一个迷宫
void createMaze()
{
	printf("输入迷宫大小:\n");
	scanf("%d", &size);
	maze = makeArray(size + 2, size + 2);//加2 表示边框
	printf("输入迷宫:\n");
	for (int i = 1; i <= size; i++)
	{
		for (int j = 1; j <= size; j++)
		{
			scanf("%d", &maze[i][j]);
		}
	}
	//加边框:1 表示不可以走
	for (int i = 0; i <= size; i++)
	{
		maze[0][i] = maze[size + 1][i] = 1;//上下两行
		maze[i][0] = maze[i][size + 1];//左右两列
	}
}
//找路径
int findPath()
{
	//偏移属性描述出来
	struct position offset[4];//0-3表示四个方向
	//往右走
	offset[0].row = 0;
	offset[0].cols = 1;
	//往左走
	offset[2].row = 0;
	offset[2].cols = -1;
	//往下走
	offset[1].row = 1;
	offset[1].cols = 0;
	//往上走
	offset[3].row = -1;
	offset[3].cols = 0;
	//选定入口
	struct position here = { 1,1 };//当前位置
	//走迷宫:记录走过的路
	//走过ID路标记为1
	maze[1][1] = 1;
	int option = 0;//下一个移动方向
	int endOption = 3;//终止方向
	while (here.row != R || here.cols != C)
	{
		//相邻的位置做移动
		int rowNum, colsNum;//记录下标变化
		while (option <= endOption)
		{
			//行的变化=原位置+偏移量 ,偏移量由方向决定
			rowNum = here.row + offset[option].row;
			colsNum = here.cols + offset[option].cols;
			//一旦确定一个方向可以走,就需去下一步
			if (maze[rowNum][colsNum] == 0)
				break;//退出循环走另一边
			//不能走就换方向测试
			option++;
		}
		//可以走
		if (option <= endOption)
		{
			//走到下一个
			pathStack[++stackTop] = here;
			//改变当前位置
			here.row = rowNum;
			here.cols = colsNum;
			//走过的路标记--->堵上
			maze[rowNum][colsNum] = 1;
			option = 0;//置0 去找下一个位置
		}
		else//option==4;表示没有可走的地方
		{
			//回到上一步去
			if (stackTop == -1)
				return 0;//无路可走表示没有路径
			//出栈方式去回退到上一步
			struct position next = pathStack[stackTop];
			stackTop--;
			//方向的处理
			if (next.row == here.row)//行没变,左右走的
			{
				//逆过来偏移公式
				option = 2 + next.cols - here.cols;
			}
			else
			{
				option = 3 + next.row - here.row;

			}
			here = next;//当前位置变成回退后的位置
		}
	}
	if (here.row == R && here.cols == C)
	{
		pathStack[++stackTop] = here;
	}
	//打印到出口后的地图
	printf("\n");
	for (int i = 1; i <= size; i++)
	{
		for (int j = 1; j <= size; j++)
		{
			printf("%d ", maze[i][j]);
		}
		printf("\n");
	}
	printf("\n");
	return 1;

}
//打印路径
void printPath()
{
	printf("路径方式:\n");
	struct position curPos;
	while (stackTop != -1)
	{
		curPos = pathStack[stackTop];
		stackTop--;
		printf("(%d ,%d)--->", curPos.row, curPos.cols);
	}
	printf("\n");
}

int main()
{
	createMaze();
	if (findPath())
	{
		printPath();
	}
	else
	{
		printf("没有路径\n");
	}
	

	return 0;
}

队列:

 链式队列:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Node
{
	int data;
	struct Node* next;
};
//创建节点过程,为队列做准备
struct Node* createNode(int data)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	if (!newNode)
	{
		return NULL;
	}
	else
	{
		newNode->data = data;
		newNode->next = NULL;
		return newNode;
	}
}
struct queue
{
	int sizeQueue;
	//链式结构实现:结构体指针
	//数组实现:数组下标
	struct Node* frontNode;//队头指针指向头节点
	struct Node* tailNode;//队尾指针指向尾节点
};
//使用一个东西表示整个队列
//描述最初状态
struct queue* createQueue()
{
	struct queue* myqueue = (struct queue*)malloc(sizeof(struct queue));
	if (!myqueue)
	{
		return NULL;
	}
	else
	{
		myqueue->sizeQueue = 0;
		myqueue->frontNode = myqueue->tailNode = NULL;
		return myqueue;
	}
}
//万金油函数
int size(struct queue* myqueue)
{
	return myqueue->sizeQueue;
}
//返回1表示不为NULL,返回0表示NULL
int empty(struct queue* myqueue)
{
	return myqueue->sizeQueue != 0;
}
//入队操作:无头链表再封装方式
void push(struct queue* myqueue, int data)
{
	struct Node* newNode = createNode(data);
	if (empty(myqueue) == 0)//队列为空
		myqueue->frontNode = newNode;
	else
		myqueue->tailNode->next = newNode;

	myqueue->tailNode = newNode;
	myqueue->sizeQueue++;
}
//出队操作:无头链表的头删法
void pop(struct queue* myqueue)
{
	//判断是否为空
	if (empty(myqueue) == 0)
	{
		printf("无法出队!");
		return;
	}
	//先保存下一个节点
	struct Node* nextNode = myqueue->frontNode->next;
	//然后删除结点
	free(myqueue->frontNode);
	myqueue->frontNode = NULL;
	//把指向头节点的指针指向新的头节点
	myqueue->frontNode = nextNode;
	myqueue->sizeQueue--;
}
//获取队头元素
int front(struct queue* myqueue)
{
	if (empty(myqueue) == 0)
	{
		printf("无法出队");
		exit(0);
	}
	else
		return myqueue->frontNode->data;
}
int main()
{
	struct queue* myqueue = createQueue();
	for (int i = 0; i < 1000; i++)
	{
		push(myqueue, i);
	}
	while (empty(myqueue))
	{
		printf("%d\t", front(myqueue));
		pop(myqueue);
	}
	return 0;
}

数组队列:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 10

struct queue
{
	int* queueMemory;  //队列容量
	int frontPos;//队头元素下标
	int tailPos;//队尾元素下标
};

struct queue* createQueue()
{
	struct queue* myqueue = (struct queue*)malloc(sizeof(struct queue));
	//描述最初状态
	//数组当队列
	//一级指针-->一维数组:动态内存申请
	if (myqueue == NULL)
	{
		printf("创建失败");
		return NULL;
	}
	else
	{
		myqueue->queueMemory = (int*)malloc(sizeof(int) * MAX);
		myqueue->frontPos = myqueue->tailPos = -1;
		return myqueue;
	}
}
//入队
void push(struct queue* myqueue, int data)
{
	//用数组时一定要判断是否满了
	if (myqueue->tailPos == MAX - 1)
	{
		printf("队列已满");
		return;
	}
	myqueue->tailPos++;
	myqueue->queueMemory[myqueue->tailPos] = data;
}

//出队和获取队头元素合一起
int pop(struct queue* myqueue)
{
	if (myqueue->frontPos == myqueue->tailPos)
	{
		printf("队列为NULL");
		return -1;
	}
	return myqueue->queueMemory[++myqueue->frontPos];
}
int empty(struct queue* myqueue)
{
	return myqueue->frontPos !=myqueue->tailPos;
}

int main()
{
	struct queue* myqueue = createQueue();
	for (int i = 0; i < MAX; i++)
	{
		push(myqueue, i);
	}
	while (empty(myqueue))
	{
		printf("%d ", pop(myqueue));
	}
	return 0;
}

数组队列~逆序整数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
	int arr[10];
	int front = 0;
	int tail = -1;
	int Num = 123456;
	while (Num)
	{
		arr[++tail] = Num % 10;
		Num /= 10;
	}
	printf("\n逆序后:");
	while (front != tail + 1)
	{
		printf("%d ", arr[front++]);
	}

	return 0;
}

优先队列:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
/*
	优先队列:根据优先权去决定你的出队的元素
	队列容量
	优先权--->数字,代表任务量,权重
	按照特殊值去做打印(选择排序)
	算法调度
	短作业优先法
*/
//数据有两部分组成
//数据本身+权值(关键字)

struct data
{
	int priority;//权值
	int element;//数据本身
};
//队列
struct priQueue
{
	int sizeQueue;//队列当前元素
	struct data queue[MAX];//队列容量
};
struct priQueue* createQueue()
{
	struct priQueue* myqueue = (struct priQueue*)malloc(sizeof(struct priQueue));
	myqueue->sizeQueue = 0;
	//数组初始化
	memset(myqueue->queue, 0, sizeof(struct data) * MAX);
	return myqueue;
}
//万金油
int empty(struct priQueue* myqueue)
{
	return myqueue->sizeQueue != 0;
}
int size(struct priQueue* myqueue)
{
	return myqueue->sizeQueue;
}
//入队,从文件中读出来,入队
void push(struct priQueue* myqueue,struct data curData)
{
	if (myqueue->sizeQueue == MAX)
	{
		printf("队列满了,无法入队!");
		return;
	}
	else
	{
		myqueue->queue[myqueue->sizeQueue] = curData;
		myqueue->sizeQueue++;
	}
}
//出队
void pop(struct priQueue* myqueue, struct data* popData)
{
	if (myqueue->sizeQueue == 0)
	{
		printf("无法出队,队列为NULL\n");
		return;
	}
	struct data minData;//去找最小权值的数据
	//假设第一个是最小的
	minData = myqueue->queue[0];
	int minIndex = 0;
	for (int i = 1; i < myqueue->sizeQueue; i++)
	{
		//比的是权值
		if (myqueue->queue[i].priority < minData.priority)
		{
			minData = myqueue->queue[i];
			minIndex = i;
		}
	}
	//popData:指针        muqueue->queue[minINdex]:结构体
	*popData = myqueue->queue[minIndex];
	//调整队列,做一个伪删除
	for (int i = minIndex; i < myqueue->sizeQueue; i++)
	{
		myqueue->queue[i] = myqueue->queue[i + 1];
	}
	myqueue->sizeQueue--;
}

int main()
{
	struct priQueue* myqueue = createQueue();
	struct data readData;
	FILE* fp = fopen("1.txt", "r");
	if (fp == NULL)
	{
		printf("打开文件失败");
		return 0;
	}
	while(!feof(fp))
	{
		fscanf(fp, "%d %d\n", &readData.element, &readData.priority);
		push(myqueue, readData);
	}
	fclose(fp);
	int workIndex = 1;
	printf("\t序号\t编号\t工作量\n");
	while (empty(myqueue))
	{
		pop(myqueue, &readData);
		printf("\t%d\t%d\t%d\n", workIndex, readData.element, readData.priority);
		workIndex++;
	}


	return 0;
}

 

 线性结构:顺序表:

数组结构

顺序表:顺序表的内存,顺序表的索引--->数组下标


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct linerList
{
	char* element;//以存储char类型的数据
	int arrayLength;//顺序表的最大长度
	int listSize;//顺序表当前元素个数
};
//顺序表的创建
struct linerList* createlist(int capacity)
{
	if (capacity < 1)
	{
		printf("创建顺序表失败!\n");
		return NULL;
	}
	else
	{
		struct linerList* list = (struct linerList*)malloc(sizeof(struct linerList));
		list->listSize =0;
		list->arrayLength = capacity;
		list->element = (char*)malloc(sizeof(capacity));
		return list;
	}
}

//二维数组的扩充
void changeArray(char** array, int oldLength, int newLength)
{
	if (newLength < 0)
	{
		printf("数组扩充失败\n");
		return;
	}
	int length = oldLength > newLength ? oldLength : newLength;
	*array =(char*)realloc(*array, length * sizeof(char));
}
//移动数组元素
void copyBackward(char* array,int arrayNum,int theIndex)
{
	for (int i = arrayNum; i > theIndex; i--)
	{
		array[i] = array[i - 1];
	}
}
//插入元素
void insertElement(struct linerList* list,int theIndex,int theElement)
{
	//索引无效
	if (theIndex<0 || theIndex>list->listSize)
	{
		printf("索引无效");
		return;
	}
	//插入的索引正好等于数组下标
	if (list->listSize == list->arrayLength)
	{
		//扩展数组
		changeArray(&list->element, list->arrayLength, 2 * list->arrayLength);
		list->arrayLength = 2 * list->arrayLength;
	}
	//储存
	copyBackward(list->element, list->listSize, theIndex);
	list->element[theIndex] = theElement;//在前索引下存储当前元素
	list->listSize++;

}
//删除需要把后面的元素往前移
void copyFrontward(char* array, int arrayNum, int theIndex)
{
	for (int i = theIndex; i < arrayNum; i++)
	{
		array[i] = array[i + 1];
	}
}
//删除
void deleList(struct linerList* list,int theIndex)
{
	if (theIndex < 0 || theIndex >= list->listSize)
	{
		printf("无索引,删除失败");
		return;
	}
	else
	{
		copyFrontward(list->element, list->listSize, theIndex);
		list->listSize--;
	}
}
void printList(struct linerList* list)
{
	for (int i = 0; i < list->listSize; i++)
	{
		printf("%c ", list->element[i]);
	}
	printf("\n");
}
int main()
{
	struct linerList* list = createlist(2);
	insertElement(list,0, 'A');
	insertElement(list, 1, 'b');
	insertElement(list, 2, 'K');
	insertElement(list, 2, 'P');
	deleList(list, 0);
	printList(list);



	return 0;
}

哈希结构:

 哈希:数据和地址的一种映射关系

映射关系:数学中的函数关系:哈希构造函数

y(x)=x;  直接地址法

哈希地址:不是指真正意义上的地址(指针),抽象的参照地址

举例:数组中数组下标就可以充当哈希地址

数据1 2 19 11 23

y=x%10;//0~9

哈希冲突:在哈希地址中已经存在元素

处理哈希冲突方案:1.开放地址法2.数组链表的方式


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//数组hash
struct pair
{
	int first;//构造一个关键字为构建hash地址做准备
	char second[20];//数据
};

struct hashTable
{
	struct pair **table;//为什么初始化二级指针,便于判断为NULL的时候
	int divisor; // y=x%dividor
	int sizeHash;
};

struct hashTable* createHash(int divisor)
{
	struct hashTable* hash = (struct hashTable*)malloc(sizeof(struct hashTable));
	hash->divisor=divisor;
	hash->sizeHash = 0;
	hash->table = (struct pair**)malloc(sizeof(struct pair) * hash->divisor);
	//hash->table[divisor]:一级指针
	for (int i = 0; i < divisor; i++)
	{
		hash->table[i] = NULL;
	}
	return hash;
}
//找到正确的地址去做插入
int search(struct hashTable* hash, int first)
{
	int pos = first % (hash->divisor);//value%divisor
	int curPos = pos;
	do
	{
		if (hash->table[curPos] == NULL || hash->table[curPos]->first == first)
		{
			//hash地址中没有元素或者相同键值(first)的元素返回
			return curPos;
		}
		curPos = (curPos + 1) % (hash->divisor);//每一次往后移一位
	} while (curPos != pos);
	return curPos;
}
//哈希插入
void insertHash(struct hashTable* hash, struct pair data)
{
	int pos = search(hash, data.first);
	if (hash->table[pos] == NULL)
	{
		hash->table[pos] = (struct pair*)malloc(sizeof(struct pair));
		memcpy(hash->table[pos], &data, sizeof(struct pair));
	}
	else//冲突处理
	{
		if (hash->table[pos]->first == data.first)
		{
			strcpy(hash->table[pos]->second, data.second);
		}
		else
		{
			printf("表满了,无法插入");
			return;
		}
	}
}
//打印
void printHash(struct hashTable* hash)
{
	for (int i = 0; i < hash->divisor; i++)
	{
		if (hash->table[i] == NULL)
			printf("NULL\n");
		else
			printf("%d %s\t\n", hash->table[i]->first, hash->table[i]->second);
	}
}
int main()
{
	struct hashTable* hash = createHash(10);
	struct pair array[5] = { 1,"循环",11,"信息",9,"上厕所",19,"bscc",10,"试试水" };
	for (int i = 0; i < 5; i++)
	{
		insertHash(hash, array[i]);
	}
	printHash(hash);
	return 0;
}

 先把代码抄下来,有点懵还不理解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Luckys-Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值