数据结构代码实现

导论

(1)数据结构是什么?

研究如何在计算机中存储数据,

表现为:操作,操作的实现以及实现的成本。

(2)分为:数学模型和逻辑模型(也称为抽象数据类型 ADT)

抽象数据类型: 没有具体的实现细节

1、单链表

概念

静态列表 --> 数组

动态列表 --> 链表
在这里插入图片描述

//  c++ 写法
struct Node{
int data;
Node *next; // 存储下一个节点的地址

} 称为一个节点

Node *temp = new Node();


头结点:作为变量,存储第一个节点的地址
头结点作全局变量 时:注意不要修改头结点, 使用新的节点代替头结点进行操作。
头结点作局部变量: 使用方法进行操作时,需要在函数参数中头结点,传的是头结点的地址。
局部变量: 在函数执行期间存在
全局变量:在程序运行期间一直存在

数组链表-比较

数组链表
访问元素O(1) 直接访问O(n) 需要从头开始遍历
插入 从头插入O(n) 需要移动元素O(1) 直接创建新节点
插入 从尾部插O(1) 直接插 或者 O(n) 数组没有空余位置需要开辟新空间遍历到尾部 需要O(n)
插入 从中间插入O(n)一般情况下平均需要移动n/2 个位置O(n)
使用简单在c/c++ 中会出现段错误或内存泄漏

链表插入(头插法)

// **头插法   head 作全局变量** 注意插入函数的变化
#include<stdio.h>
#include<stdlib.h>
 
struct Node{
	int data ;
	Node *next; // 指针域 
	
};
Node *head = new Node();   // 全局变量 头结点,指向空 

void Insert(int x){
	Node * temp = new Node(); 
//	struct	Node *temp = (Node*)malloc(sizeof(struct Node)); // c 语言 
	temp->data = x; 
	temp-> next =head; // 不可颠倒顺序 
	head =temp; 
}
void Print(){
	Node *temp = head; // 创建新节点 代替 头结点 ,即新节点指向第一个节点。
	printf("list is:\n"); 
	while(temp!= NULL){
		printf("%d\n",temp->data);
		temp = temp->next;
	}

}
int main(){
	head = NULL;
	printf("How many numbers");
	int n,i,x;
	scanf("%d",&n);
	for (i =0;i<n;i++){
		printf("Enter the number");
		scanf("%d",&x);
		Insert(x);
		Print();
	}
	return 0;
} 
// head 作局部变量
#include<stdio.h>
#include<stdlib.h>
 
struct Node{
	int data ;
	Node *next; // 指针域 
	
}; 
Node *Insert( Node*head,int x){
	Node * temp = new Node(); 
//	struct	Node *temp = (Node*)malloc(sizeof(struct Node)); // c 语言 
	temp->data = x; 
	temp-> next =head; // 不可颠倒顺序 
	head =temp; 
	return head;
}
void Print(Node* head){
	printf("list is:\n"); 
	while(head!= NULL){
		printf("%d\n",head->data);
		head = head->next;
	}

}
int main(){
	Node *head = NULL;   // 局部变量 
	printf("How many numbers");
	int n,i,x;
	scanf("%d",&n);
	for (i =0;i<n;i++){
		printf("Enter the number");
		scanf("%d",&x);
		head = Insert(head,x); //insert函数 返回头结点地址 
		Print(head);
	}
	return 0;
} 

结果:
在这里插入图片描述

在任意位置插入

需要考虑两点:
在头部插入
在其他位置插入 ,需要找到第n-1 的位置

#include<stdio.h>
#include<stdlib.h>
 
struct Node{
	int data ;
	Node *next; // 指针域 
	
}; 

Node *Insert( Node*head,int d,int x){
	//创建新节点 
	Node * temp = new Node(); 
	temp->data = d; 
	temp->next =NULL;
	
	// 在第一个位置插入 
	if(x ==1){
		temp-> next =head;  // 不可颠倒顺序 
		head =temp; 
		return head;  
	}
	
	Node *pre_node = head;  // 指向head 
	// 找到第n-1 个位置
	for(int i=0;i< x-2;i++){
		pre_node = pre_node-> next; 
	} 
	temp->next = pre_node->next;
	pre_node->next=temp;	
	return head;
}

void Print(Node* head){
	printf("list is:\n"); 
	while(head!= NULL){
		printf("%d\n",head->data);
		head = head->next;
	}

}
int main(){
	Node *head = NULL;   // 局部变量 
	int n;  // 次数 
	int d,x;   //数据 ,位置 
	printf("Enter the numbers\n");
	scanf("%d",&n);
	while(n--)
	{
	printf("Enter data and position  for example: 3 1\n"); 
	scanf("%d %d",&d,&x);
	head = Insert(head,d,x); //insert函数 返回头结点地址 
	Print(head);
	}
	return 0;
} 

结果:
在这里插入图片描述

删除任意位置的节点

节点是动态内存分配的, 是内存堆的一部分
所以在c/c++ 中必须显示释放内存

#include<stdio.h>
#include<stdlib.h>
 
struct Node{
	int data ;
	Node *next; // 指向节点的指针 
	
}; 
Node *head = NULL; // 全局变量
 
void Insert( int d,int x){ // d 代表数据 x 代表位置
	//创建新节点 
	Node * temp = new Node(); 
	temp->data = d; 
	temp->next =NULL;	
	// 在第一个位置插入 
	if(x ==1){
		temp-> next =head; 
		head =temp; 
		return ;  
	}
	Node *pre_node = head;  // 指向head 
	// 找到第n-1 个位置
	for(int i=0;i< x-2;i++){
		pre_node = pre_node-> next; 
	} 
	temp->next = pre_node->next;  // 插入节点
	pre_node->next=temp;	
	return ;
}

void Delete(int n){   // n 代表位置
	Node *pre_node = head;  // 指向head 
	if(n==1){
		head = pre_node->next;
//		delete(pre_node);
		free(pre_node); 
		return ;  //   易错 
	}
	// 找到第n-1 个位置
	for(int i=0;i< n-2;i++){
		pre_node = pre_node -> next; 
	} 
	Node *temp = pre_node->next;
	pre_node->next = temp->next;	
//	free(temp);  // c 语言
	delete(temp); 
//	return;
}

void Print(){
	Node *temp= head;
	printf("list is:\n"); 
	while(temp!= NULL){
		printf("%d\n",temp->data);
		temp = temp->next;
	}

}
int main(){
//	int n;  // 次数 
//	int d,x;   //数据 ,位置 
//	printf("Enter the numbers\n");
//	scanf("%d",&n);
//	while(n--)
//	{
//	printf("Enter data and position  for example: 3 1\n"); 
//	scanf("%d %d",&d,&x);
//	Insert(d,x); //insert函数 返回头结点地址 
//	Print();
//	}
    Insert(3,1);
    Insert(2,2);
    Insert(4,3);
	printf("delete form list: enter a position \n");
	int dd;
	scanf("%d",&dd);
	Delete(dd);
	Print();
	
	 
	return 0;
} 

结果
在这里插入图片描述

迭代反转链表

在这里插入图片描述

需要设置三个指针,一个保存当前值,一个保存前面,一个保存后面。将指针的指向翻转。
考虑 链表为空的特殊情况!!
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
 
struct Node{
	int data ;
	Node *next; // 指向节点的指针 
	
}; 
Node *head = NULL; // 全局变量
 
void Insert( int d,int x){ // d 代表数据 
	//创建新节点 
	Node * temp = new Node(); 
	temp->data = d; 
	temp->next =NULL;	
	// 在第一个位置插入 
	if(x ==1){
		temp-> next =head;  // 不可颠倒顺序 
		head =temp; 
		return ;  
	}
	Node *pre_node = head;  // 指向head 
	// 找到第n-1 个位置
	for(int i=0;i< x-2;i++){
		pre_node = pre_node-> next; 
	} 
	temp->next = pre_node->next;
	pre_node->next=temp;	
	return ;
}

void Delete(int n){
	Node *pre_node = head;  // 指向head 
	if(n==1){
		head = pre_node->next;
//		delete(pre_node);
		free(pre_node); 
		return ;  //   易错 
	}
	// 找到第n-1 个位置
	for(int i=0;i< n-2;i++){
		pre_node = pre_node -> next; 
	} 
	Node *temp = pre_node->next;
	pre_node->next = temp->next;	
//	free(temp);  // c 语言
	delete(temp); 
//	return;
}


void Reverse(){
	
	Node * prev = NULL , *current = head ,*after;
	while(current!=NULL){
		after = current->next;
		current->next =prev;
		prev= current;
		current = after;	
	}
	head =prev; //重点!!! 
}


void Print(){
	Node *temp= head;
	printf("list is:\n"); 
	while(temp!= NULL){
		printf("%d\n",temp->data);
		temp = temp->next;
	}

}
int main(){
//	int n;  // 次数 
//	int d,x;   //数据 ,位置 
//	printf("Enter the numbers\n");
//	scanf("%d",&n);
//	while(n--)
//	{
//	printf("Enter data and position  for example: 3 1\n"); 
//	scanf("%d %d",&d,&x);
//	Insert(d,x); //insert函数 返回头结点地址 
//	Print();
//	}
    Insert(3,1);
    Insert(2,2);
    Insert(4,3);
    Print();
//    // 删除元素 
//	printf("delete form list: enter a position \n");
//	int dd;
//	scanf("%d",&dd);
//	Delete(dd);
//	Print();
	// 翻转链表 
	 Reverse();
	 Print();
	return 0;
} 

结果

在这里插入图片描述

递归反转遍历链表

递归使用栈空间多次调用函数
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
 
struct Node{
	int data ;
	Node *next; // 指针域 
	
}; 

Node *Insert( Node*head,int d,int x){
	//创建新节点 
	Node * temp = new Node(); 
	temp->data = d; 
	temp->next =NULL;
	
	// 在第一个位置插入 
	if(x ==1){
		temp-> next =head;  // 不可颠倒顺序 
		head =temp; 
		return head;  
	}
	
	Node *pre_node = head;  // 指向head 
	// 找到第n-1 个位置
	for(int i=0;i< x-2;i++){
		pre_node = pre_node-> next; 
	} 
	temp->next = pre_node->next;
	pre_node->next=temp;	
	return head;
}

void Print(Node* temp){
 		if(temp == NULL) {
 		 printf("\n");
		 return;
		 } 
		 printf("%d",temp->data); // 先输出
		 Print(temp->next);  // 然后递归调用

}
void ReversePrint(Node* temp){
 		if(temp==NULL) {
 		 printf("\n");
		 return;	
		 }
		 ReversePrint(temp->next);  // 先一层层的往下进行递归调用
		 printf("%d",temp->data);   // 递归到边界条件后在开始一层层的从下往上输出
}

int main(){
	Node *head= NULL;
    head = Insert(head,3,1); 
    head = Insert(head,4,2); 
    head = Insert(head,5,3); 
    head = Insert(head,6,4); 
    Print(head);
    printf("reverse list:");
    ReversePrint(head);
	return 0;
} 

结果
在这里插入图片描述

递归反转链表

栈中存储的是结构体的地址
在这里插入图片描述

#include<stdio.h>
//#include<stdlib.h>
struct Node{
	int data ;
	Node *next; // 指针域 
	
};  

// 全局变量
Node * head = NULL;

//反转链表
void Reverse(Node* p){
 	if(p->next == NULL){  //  递归出口:head 指向最后一个节点 
 		head = p;  
 		return;  // 重要!! 
	 }	
	 Reverse(p->next);     
	 Node * q = p ->next ;
	 q-> next = p;
	 p->next = NULL;
}
//插入
void Insert( int d,int x){
	//创建新节点 
	Node * temp = new Node(); 
	temp->data = d; 
	temp->next = NULL;
	
	// 在第一个位置插入 
	if(x ==1){
		temp-> next =head;  // 不可颠倒顺序 
		head =temp; 
		return ;  
	}
	
	Node *pre_node = head;  // 指向head 
	// 找到第n-1 个位置
	for(int i=0;i< x-2;i++){
		pre_node = pre_node-> next; 
	} 
	temp->next = pre_node->next;
	pre_node->next=temp;	

}

// 递归打印 
void Print(Node* temp){
 		if(temp == NULL) {
 		 printf("\n");
		 return;
		 } 
		 printf("%d ",temp->data); // 先输出
		 Print(temp->next);  // 递归调用

}

int main(){
	Insert(3,1);
	Insert(4,2);
	Print(head);
    Reverse(head);
	Print(head); 
 
	return 0;
} 

在这里插入图片描述

2、双链表

优点: 可以反向查询
在这里插入图片描述

双链表实现

在这里插入图片描述

#include <stdio.h>

using namespace std;

struct Node{
	int data;
	Node *prev;
	Node *next;
}; 

Node *head =NULL;

//生成新节点 
Node* GetNode(int x){
	Node *temp= new Node();
	temp->data=x;
	temp->prev=NULL;
	temp->next=NULL; 
	return temp;
}

//头插法 
void InsertHead(int x){
	Node *newNode  = GetNode(x);
	//链表为空
	if(head == NULL) 
	{
		head =newNode ;
		return;
	 } 
	head ->prev = newNode; // head的pre 指向新节点 
	newNode ->next = head; //新节点的next指向head 
	head = newNode;  
}

// 尾插法 
void InsertTail(int x){
	Node* temp = head;  //  指向head 的节点
	Node *newNode  = GetNode(x);
	//链表为空
	if(head == NULL) 
	{
		head = newNode;
		return;
	 } 
	while( temp->next != NULL)
	      temp = temp->next; // 找最后一个节点
	 temp->next = newNode;
	 newNode->prev = temp;  	 
 }
	

//打印输出 
void Print(){
	Node *temp = head;
	while( temp != NULL){
		printf("%d ",temp->data);
		temp = temp->next; 
	}
}

int main(){
	
	InsertHead(2);
	InsertHead(3);
	InsertHead(4);
	printf(" head List is :\n");
	Print(); // 头插法 4 3 2 
	printf("\n");
	
	InsertTail(7);
	InsertTail(6);
	InsertTail(5); 
	InsertTail(4);
	printf("tail List is :\n");
	Print();   // 4 3 2 7 6  5 4 
	 
	return 0;
} 

在这里插入图片描述

3、 栈

应用场景:
(1)实现递归,递归就是函数调用链
(2)文本编辑器或图像编辑器的撤回操作,ctrl +z
(3)编译器使用栈 验证 源码的括号是否匹配,不匹配报错

数组 实现栈

边界条件:
数组满时,不能push (往栈中存数据)
push 的时间复杂度最坏为O(n)因为可能数组长度不够,需要重新开辟空间。
数组为空时,不能pop (从栈中去除数据)

#include<stdio.h>

#define size 100
int Stack[size];
int top = -1;
// 数据压栈
void Push(int x){
	if(top == size-1){
		printf("ERROR: stack overflow !"); 
		return ;
	}
	top++;
	Stack[top]=x;
	// Stack[++top] = x;	
}
// 弹出栈
void Pop(){
	if(top == -1){
		printf("ERROR: No element to pop!");
		return;
	}	
	top--; 
} 
//输出栈顶元素
int Top(){
 	return Stack[top];	
}
// 栈是否为空
bool Empty(){
	if(top == -1){
		return true;
	}
} 
// 输出栈中元素
void Print(){
	printf("Stack is:");
	for(int i= 0;i<=top;i++){
		printf("%d ",Stack[i]);
	}
	printf("\n");
}
int main(){
	
    Push(2);
    Push(4);
    Print();
    Pop();
    Print();
 
	return 0;
} 

结果
在这里插入图片描述

用链表实现栈

在这里插入图片描述
在这里插入图片描述

#include<stdlib.h>
#include<iostream>
#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

struct Stack{
	int data;
	Stack *next;
}; 

//Stack *top= new Stack(); 
Stack *top =NULL;

// 链表的头插
void Push(int x){
	Stack *temp = new Stack(); 
//	Stack *temp = NULL;    // 和上句代码作用不一样
	temp ->data = x;
	temp ->next = top;
	top =temp;	
	
}

//  链表的删除
void Pop(){	
	Stack *temp = new Stack();
	if(top == NULL) return;
	temp = top;        // 将top节点的地址传给新节点temp ,top  和 temp 指向同一个 
	top = top ->next;
	delete(temp); 
	
}

// 链表的输出
void Print(){
	Stack *temp = top; // 创建新节点 ,将top 节点的地址传给新节点
	printf("Stack is: \n ");
	while(temp != NULL){
		printf("%d ",temp->data);
		temp = temp->next;
	} 	
}



int main(){
 	Push(2);
 	Push(4);
 	Push(3);
 	Print();
 	Pop();
 	printf("\n");
 	Print();
	return 0;
} 

结果
在这里插入图片描述

反转字符串

c++ 中自己实现栈,可以用数组或者链表在这里插入图片描述

  • 补充

使用c++ 自带的栈
#include< stack >
gets
头文件<stdio.h>
char *gets(char *str) 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
strlen
#include <string.h>
strlen()函数用来计算字符串的长度,其原型为:
unsigned int strlen (char *s);
【参数说明】s为指定的字符串。
strlen()用来计算指定的字符串s 的长度,不包括结束字符"\0"。
【返回值】返回字符串s 的字符数。

#include<stdlib.h>
#include<iostream>
#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

// 使用数组 反转字符串 
void Reverse(char arr[],int n){
	stack<char> s;
	// loop for push 
	for(int i=0;i<n;i++){
		s.push(arr[i]);
	}
	// loop for pop
	for(int i= 0;i<n;i++){
		arr[i] = s.top();
		s.pop();	
	}
	
}

int main(){
	char arr[12];
	printf("Enter a string :");
	gets(arr);
	Reverse(arr,strlen(arr));
	printf(arr);
	return 0;
} 
#include<stdlib.h>
#include<iostream>
#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

// 使用两个变量反转字符串 
void Reverse(char arr[],int i ,int j){
	while(i<=j){
		char temp;
		temp = arr[i];
		arr[i] = arr[j];
		arr[j] =temp;
		i++;
		j--;
	} 
}

int main(){
	char arr[12];
	printf("Enter a string :");
	gets(arr);	
	Reverse(arr,0,strlen(arr)-1);
	printf(arr);
	return 0;
} 

char arr[ ] 等价于char *arr
也可以 通过 Reverse(arr,strlen(arr)); 达到只转换某几个的效果

#include<stdlib.h>
#include<iostream>
#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

// 使用栈反转字符串 
void Reverse(char *arr,int n ){
	stack<char> s;
	int i;
	for(i=0;i<n;i++) 
		s.push(arr[i]);
	for(i=0;i<n;i++){
		arr[i]=s.top();
		s.pop();
	}

}

int main(){
	char arr[12];
	printf("Enter a string :");
	gets(arr);	
	Reverse(arr,strlen(arr));
	printf(arr);
	return 0;
} 

结果
在这里插入图片描述

反转链表

(1)压入所有的元素
在这里插入图片描述
(2)出栈
在这里插入图片描述(3)将最后一个节点指向null
在这里插入图片描述

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

using namespace std;

struct Node{
	int data;
	Node *next;
}; 

stack<Node *> s;  
Node *head =NULL;

// 用栈反转链表 
void Reverse(){
	
   // 将结点  压栈
   Node * temp = head ;    
   while(temp!=NULL){   
		s.push(temp);       
		temp = temp->next;
   }
   
   //     出栈 
   temp =s.top();  // 指向栈顶 
   head =temp;   // 设置头结点 
   s.pop();    
   while(!s.empty()){
   		temp->next =  s.top();   // 实现 next的指针指向反转
   		s.pop();
   		temp = temp ->next;
   }
   temp->next =NULL;  // 最后一个节点指向null !!! 
   
}



void Insert(int x){
	Node *temp = new Node();
	temp ->data=x;
	temp ->next = head;
	head = temp;
}
void Print(){
	Node *temp =head;
	while(temp!= NULL){
		printf("%d ",temp->data);
		temp =temp->next; 
	}
}

int main(){
	Insert(2);
	Insert(3);
	Insert(4);
	printf(" List is :\n");
	Print(); // 头插法 4 3 2 
	Reverse();
	printf("\n");
	printf("  Recerser List is :\n");
	Print();   // 2 3 4 
	 


	return 0;
} 

== 结果==
在这里插入图片描述

括号匹配


#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

stack<char> sk;   // 字符栈
char s[] = "{(([]))}";

// 检查是否匹配
bool check(char l,char r ){
	if(l =='('&& r ==')') return true;
	if(l =='{'&& r =='}') return true;
	if(l =='['&& r ==']') return true;
	if(l ==')'&& r =='(') return true;
	if(l =='}'&& r =='{') return true;
	if(l ==']'&& r =='[') return true;
	return false;
}

bool checkBracket(char s[]){
	  // 循环
    // 碰到左括号压入栈中
    
   for(int i=0; i<strlen(s) ;i++){
   	if(s[i]=='{'||s[i]=='('||s[i]=='[')
   	     sk.push(s[i]);  
 	// 碰到右括号 判断是否 和左括号匹配
   // 栈为空,或者不匹配 直接退出
   // 否则 弹出 元素,接着检查剩下元素 
 	else if(s[i]==')'||s[i]=='}'||s[i]==']'){
 		if( sk.empty() ||  ( !check(s[i],sk.top()) ) ){
 	 		return false ;
		}
		else sk.pop();
	}
   	    
   } 
   
   // 最后判断 栈中为空  则匹配成功
   return sk.empty()?true:false;
} 





int main(){
   
   if(checkBracket(s))
   printf(" matching ");
   else printf("No matching ");
} 

在这里插入图片描述

表达式

2 ”^"3 "^ ” 2“ 连续幂成 从右往左算。
a+b的 前缀表达式(+a b), 中缀表达式(a +b),后缀表达式 (a b +)

栈实现后缀表达式求值

从前往后扫描 ,先弹出的是 op2
在这里插入图片描述
在这里插入图片描述


#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

stack<char> sk;   // 字符栈



//数字 
bool Operand(char c){
	if(c>='0'&&c<='9')
	 return true;
	else return false;
} 


//字符 
bool Operator(char c ){

	if(c=='+'||c=='-'||c=='*'||c=='/')
	return true;
	else return false;	
} 

//计算 
int Perform(char c,int op1,int op2){
	int res;
	switch(c){
		case '+': res = op1+op2; break;
		case '-': res = op1-op2; break;
		case '*': res = op1*op2; break;
		case '/': res = op1/op2; break;
		
	}
	return res;
} 

//匹配 
int  Match(char ch[]){
 //循环,数字压入栈中, 
 //碰到符号,则从栈中弹出两个元素,注意弹出顺序 
 // 计算,将结果压入栈中 
 int res,op1,op2;
 for (int i=0;i<strlen(ch);i++){
 
 	if(Operand(ch[i])) sk.push(ch[i]-'0');  // 字符转数字
 	else if( Operator(ch[i]) ) {
 		 op2=sk.top(); sk.pop();   			//先弹出的是第二个数字 
		 op1=sk.top();sk.pop();
		 res=Perform(ch[i],op1,op2);		 //计算
		 sk.push(res);		 					 // 结果压入栈中
	 } 	
 }
 return res;  
} 


int main(){
	char ch[] = "23*45*+9-";
   printf("%d ",Match(ch));
} 

在这里插入图片描述

前缀表达式求值

从后往前扫描
碰到数入栈,碰到符号从栈中弹出两个数
先弹出的是第一个操作数
计算的结果压入栈中

举例: 3- 2 的前缀表达式为: - 3 2
先压入 2
在压入 3
碰到 -
先弹出3
在弹出2


#include<stdio.h>
#include<stack>
#include <string.h>
using namespace std;

stack<char> sk;   // 字符栈



//数字 
bool Operand(char c){
	if(c>='0'&&c<='9')
	 return true;
	else return false;
} 


//字符 
bool Operator(char c ){

	if(c=='+'||c=='-'||c=='*'||c=='/')
	return true;
	else return false;	
} 

//计算 
int Perform(char c,int op1,int op2){
	int res;
	switch(c){
		case '+': res = op1+op2; break;
		case '-': res = op1-op2; break;
		case '*': res = op1*op2; break;
		case '/': res = op1/op2; break;
	}
	return res;
} 

//前缀匹配
int  Match(char ch[]){
 //从 右向左 循环,数字压入栈中, 
 //碰到符号,则从栈中弹出两个元素,注意弹出顺序 
 // 计算,将结果压入栈中 
 int res,op1,op2;
 for (int i= strlen(ch)-1 ;i >= 0;i--){
 	
 	if(Operand(ch[i])) sk.push(ch[i]-'0');
 	else if( Operator(ch[i]) ) {
 		 op1=sk.top(); sk.pop();
		 op2=sk.top();sk.pop();
		 res=Perform(ch[i],op1,op2); 
		 sk.push(res);		
	 } 	
 }
 return res;  
} 


int main(){
	char ch[] = "-+*23*549";
   printf("%d ",Match(ch));
} 

中缀表达式变后缀表达式

没有括号的伪代码在这里插入图片描述
有括号的伪代码
在这里插入图片描述
在这里插入图片描述

4、队列

与栈的在某一端插入删除不同
队列必须是在一端插入,另一端删除。

在这里插入图片描述
在这里插入图片描述

用数组表示队列

没有 考虑数组大小 的伪代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

考虑数组大小 (即 使用循环数组) 的伪代码
在这里插入图片描述
在这里插入图片描述

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


#define N 10 

// 用循环数组实现队列 
int queue[N];
int front=-1 ,rear=-1;

//判断是否为空 
bool Isempty(){
	if(front==-1 && rear==-1){
	return true;
	} 
    return false;
}


//出队列 
void Dequeue(){
	if(Isempty()) return;
	else if(front == rear) front =rear = -1;
	else {
		front = (front+1)%N; //  重点!!!! 
	}
	
}


//入队列 
void Enqueue(int x){
	if((rear+1)%N==front)  return ;	
	else if(Isempty()){
		 front = rear =0;
	}
	else rear=(rear+1)%N;
	queue[rear]=x;
}

//队首元素 

void Front(){
	 printf("%d ",queue[front]);
}

void Print(){
	for(int i=front ;i<=rear ;i++){
		printf("%d ",queue[i]);
	}
}

int main(){
	Enqueue(1); 
 	Enqueue(2);
 	Enqueue(3);
 	Enqueue(4);  
 	Print();    //  入队  1 2 3 4
 	printf("\n");
 	Front();	// 队首 1
 	printf("\n");
 	Dequeue(); 
	Print();  // 2 3 4  

	return 0;
} 

在这里插入图片描述

用链表表示队列

数组实现时,当数组满时为了插入元素需要开辟新的空间,复杂度O(n)
当数组没有元素时,内存资源被浪费

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 补充

注意 : c语言 中 if (0)之后的代码是不执行的
C 或 C++ 中 输出 bool 变量的值 ,是用数字 1 和 0 表示,而不是 true 或 false。
Java、PHP、JavaScript 等也都支持布尔类型,但输出结果为 true 或 false。

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

// 用链表实现队列 
struct queue{
	int data;
	queue *next;
}; 

queue *front =NULL;
queue *rear =NULL;


//判断是否为空 
bool Isempty(){
	if(front==NULL && rear==NULL){
	return true;
	} 
    return false;
}


//出队列 
void Dequeue(){
	queue *temp = front;
//对空  if(Isempy) return ;    错误
	if (front== NULL) return;   //  重点 
//只剩一个元素 
	if(front ==rear) front =rear= NULL;
// 出队 
	else {
		front =front->next;
	}
	delete(temp);
}


//入队列
void Enqueue(int x){
	// 创建新节点 
	queue *temp = new queue();
    temp->data=x;
    temp->next=NULL;
    //第一次入队
	if(front ==NULL && rear ==NULL)
		front =rear =temp;
	// 入队
	rear->next=temp;
	rear =temp; 
}

//对首元素 

void Front(){
	 printf("%d ",front->data);
}

void Print(){
	queue *temp=front;
	while(temp!=NULL){
		printf("%d ",temp->data);
		temp= temp->next;
	}
}

int main(){
	
	Enqueue(1); 
 	Enqueue(2);
  	Enqueue(3);
  	Enqueue(4);   
 	Enqueue(5);
  	Enqueue(6); 
 	Print();       //  入队  1 2 3 4 5 6 
 	printf("\n");
 	Dequeue();   // 出队 2 3 4 5 6
	Print(); 
	printf("\n");
 	Front();      // 2
	 printf("\n");
 	printf("%d ",Isempty()); 
 		
	return 0;
} 

在这里插入图片描述

5、树

  • 树是用来表示层次数据的一个结构

    遍历一棵树只能从一个方向进行
    兄弟必须有一个双亲
    树是递归的数据结构(子树)

  • 应用:
    磁盘驱动器的文件系统

    组织数据,二叉搜索树快速查找

    做数据字典,动态拼写检查

    网络路由算法

二叉排序树

字符串按字典排序或者按字母排序进行查找

二叉搜索树

判断是否是二插搜索树

方法 1 可以中序遍历判断是否有序。

方法2 递归判断左子树是否小于根节点,右子树是否大于根节点,当前是否是二叉搜索树。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

递归插入与查找

在这里插入图片描述

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;

// 二叉树  想双链表
struct BstNode
{
    int data ;
	BstNode *left;
	BstNode *right;	
};

// 创建新节点 
BstNode *GetNode(int data){
	BstNode * temp = new BstNode();
	temp->data = data;
	temp->left = temp->right = NULL;
	return temp;
} 

// 递归实现插入 
BstNode* Insert( BstNode * root ,int data){
	// 树为空,设置根节点
	if(root == NULL){
		root = GetNode(data);
	} 
	// 树不空,小于则 插左边
	// 树不空,大于 插右边 
	else if(data <= root->data) {
		root->left = Insert(root->left ,data);
	}
	else if(data >= root->data) {
		root->right= Insert(root->right ,data);
	}
	return root;    // root 是局部变量 
}

// 递归实现搜索 
bool Search( BstNode * root ,int data){
	if(root == NULL){
		return false;
	} 
	else if(data == root->data) {
		return true;
	}
	else if(data <= root->data) {
		return Search(root->left ,data);
	}
	else if(data >= root->data) {
		return Search(root->right ,data);
	}
}


int main(){
   
   BstNode *root =NULL;  // 局部变量 
   root = Insert(root ,15);
   root = Insert(root ,10);
   root = Insert(root ,20);
   int number;
   cout << "Enter number to search ";
   cin >> number;
   if(Search(root,number)==true)
   printf("found");
   else printf("No found");
    
   
} 

在这里插入图片描述

找最值(迭代和递归)

最大:查找右边的子树
最小值:找最左边的子树

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
struct BstNode
{
    int data ;
	BstNode *left;
	BstNode *right;	
};

// 创建新节点 
BstNode *GetNode(int data){
	BstNode * temp = new BstNode();
	temp->data = data;
	temp->left = temp->right = NULL;
	return temp;
} 

// 递归实现插入 
BstNode* Insert( BstNode * root ,int data){
	// 树为空,设置根节点
	if(root == NULL){
		root = GetNode(data);
	} 
	// 树不空,小于则 插左边
	// 树不空,大于 插右边 
	else if(data <= root->data) {
		root->left = Insert(root->left ,data);
	}
	else if(data >= root->data) {
		root->right= Insert(root->right ,data);
	}
	return root;    // root 是局部变量 
}

// 迭代 找最小值 
int FindMin(BstNode *root){
	// 树为空
	if(root == NULL) {
		cout << " Error caused by the empty tree!"<< endl;
		return -1; 
	} 
	// 树不空 
	while(root->left != NULL){
		root = root->left;
	}
	return root->data;
}
// 递归找最小值 
int ReFindMin(BstNode *root){
	// 边界 
	if(root == NULL) {
		cout << " Error caused by the empty tree!"<< endl;
		return -1 ; 
	} 
	else if(root->left == NULL){
		return root->data;
	}
	return ReFindMin(root->left);
}

// 递归找最大值 
int ReFindMax(BstNode *root){
	// 边界 
	if(root == NULL) {
		cout << " Error caused by the empty tree!"<< endl;
		return -1 ; 
	} 
	else if(root->right == NULL){
		return root->data;
	}
	return ReFindMax(root->right);
}




int main(){
   
   BstNode *root =NULL;  // 局部变量 
   root = Insert(root ,15);
   root = Insert(root ,23);
   root = Insert(root ,20);
   root = Insert(root ,8);
   root = Insert(root ,12);
   root = Insert(root ,2);
   cout << "min :" << FindMin(root) << endl;
   cout << "min :" << ReFindMin(root) << endl; 
   cout << "max : "<< ReFindMax(root) << endl; 
   
} 

在这里插入图片描述

二叉搜索树的删除

删除叶子节点 直接删
删除 非叶子节点
– 当有一个孩子
– 有两个孩子 变成有一个节点的情况 — 通过找右子树的最小值或者左子树的最大值

#include <iostream>
using namespace std;
struct BstNode
{
    int data ;
	BstNode *left;
	BstNode *right;	
};

// 创建新节点 
BstNode *GetNode(int data){
	BstNode * temp = new BstNode();
	temp->data = data;
	temp->left = temp->right = NULL;
	return temp;
} 
// 递归实现插入 
BstNode* Insert( BstNode * root ,int data){
	// 树为空,设置根节点
	if(root == NULL){
		root = GetNode(data);
	} 
	// 树不空,小于则 插左边
	// 树不空,大于 插右边 
	else if(data <= root->data) {
		root->left = Insert(root->left ,data);
	}
	else if(data >= root->data) {
		root->right= Insert(root->right ,data);
	}
	return root;    // root 是局部变量 
}

//找到最小值 ,返回地址 
BstNode *FindMin(BstNode *temp){
	while(temp->left != NULL){
		temp = temp->left;
	} 
	return temp;
}


//删除一个节点 
BstNode * Delete(BstNode *root ,int data){
	if(root == NULL) return NULL;
	// 要删除的数据小于根节点,找左子树 
	else if (data < root->data) root->left = Delete(root->left, data);	
	// 要删除的数据大于根节点,找右子树 
	else if (data > root->data) root->right = Delete(root->right,data);
	
	// 删除数据 
	else {
	// 没有孩子
	if(root->left == NULL && root->right == NULL){
		delete root;
		root = NULL; 
	} 
	// 有一个孩子
	else if(root->left == NULL){
		// 右孩子变成根节点 
		BstNode *temp = root;
		root = root->right; 
		delete temp;
	} 
	else if(root->right == NULL){
		// 指向左孩子
		BstNode *temp = root;
		root = root->left; 
		delete temp;
	} 
	// 有两个孩子 
	else{
		// 找到右孩子的最小值 或者找左子树最大值 
		BstNode *temp = FindMin(root->right);
		// 将最小值赋到root 
		root ->data = temp->data;
		// 删除最小值 
		root->right = Delete(root->right,temp->data); 
	}
	} 
	return root;
}

// 前序遍历 
void PreOrder(BstNode *root){
	// 边界
	if(root == NULL) {
		return ;
	} 
	cout << root->data<< " ";
	PreOrder(root->left);
	PreOrder(root->right ); 
} 


int main(){
   BstNode *root =NULL;  // 局部变量 
   root = Insert(root ,15);
   root = Insert(root ,23);
   root = Insert(root ,20);
   root = Insert(root ,8);
   root = Insert(root ,12);
   root = Insert(root ,2); 
   cout << " PreOrder is :";
   PreOrder(root) ;
   cout << endl;
   Delete(root,15) ;
   cout << " NewOrder is :";
   PreOrder(root) ;
    
    
} 

在这里插入图片描述

二叉树的中序后继节点

二叉树高度

在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
struct BstNode
{
    int data ;
	BstNode *left;
	BstNode *right;	
};

// 创建新节点 
BstNode *GetNode(int data){
	BstNode * temp = new BstNode();
	temp->data = data;
	temp->left = temp->right = NULL;
	return temp;
} 

// 递归实现插入 
BstNode* Insert( BstNode * root ,int data){
	// 树为空,设置根节点
	if(root == NULL){
		root = GetNode(data);
	} 
	// 树不空,小于则 插左边
	// 树不空,大于 插右边 
	else if(data <= root->data) {
		root->left = Insert(root->left ,data);
	}
	else if(data >= root->data) {
		root->right= Insert(root->right ,data);
	}
	return root;    // root 是局部变量 
}

// 比大小 
int Max(int a,int b){
	return a >= b ? a : b; 
}
// 递归找高度 
int ReFindHeight(BstNode *root){
	// 边界 
	if(root == NULL) {
		return 0 ; 
	} 
	return Max( ReFindHeight(root->left) , ReFindHeight(root->right)) + 1;
}


int main(){
   
   BstNode *root =NULL;  // 局部变量 
   root = Insert(root ,15);
   root = Insert(root ,23);
   root = Insert(root ,20);
   root = Insert(root ,8);
   root = Insert(root ,12);
   root = Insert(root ,2);
   cout << "height :" << ReFindHeight(root) << endl; 
} 

树的遍历

分为广度遍历和深度遍历
深度遍历又分为 前序,中序,后序遍历

树的广度遍历

队列 实现链表
当节点出队时 保证 该节点的左右节点都入队

在这里插入图片描述

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
struct BstNode
{
    int data ;
	BstNode *left;
	BstNode *right;	
};

// 创建新节点 
BstNode *GetNode(int data){
	BstNode * temp = new BstNode();
	temp->data = data;
	temp->left = temp->right = NULL;
	return temp;
} 

// 递归实现插入 
BstNode* Insert( BstNode * root ,int data){
	// 树为空,设置根节点
	if(root == NULL){
		root = GetNode(data);
	} 
	// 树不空,小于则 插左边
	// 树不空,大于 插右边 
	else if(data <= root->data) {
		root->left = Insert(root->left ,data);
	}
	else if(data >= root->data) {
		root->right= Insert(root->right ,data);
	}
	return root;    // root 是局部变量 
}


// 时间复杂度o(n) 空间复杂度  O(1) <-- 一个分支   o(n) <-- 其他分支 
void LevelOrder(BstNode *root){
	// 边界
	if(root == NULL) {
		return ;
	} 
	queue<BstNode *> qe;
	// 根元素入队
	qe.push(root);

	while(!qe.empty()){
		BstNode *cur = qe.front(); 
		// 输出值 
		if(cur != NULL)  cout << cur->data << " ";	
		// 左孩子入队
		if(cur->left != NULL) qe.push(cur->left);
		// 右孩子入队
		if(cur->right != NULL) qe.push(cur->right);
		// 从队中弹出根元素 	
		qe.pop();
	}
	
	 
} 


int main(){
   
   BstNode *root =NULL;  // 局部变量 
   root = Insert(root ,15);
   root = Insert(root ,23);
   root = Insert(root ,20);
   root = Insert(root ,8);
   root = Insert(root ,12);
   root = Insert(root ,2); 
   cout << " level order is: "<< endl;
    LevelOrder(root); 
} 

在这里插入图片描述

树的深度遍历

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
struct BstNode
{
    int data ;
	BstNode *left;
	BstNode *right;	
};

// 创建新节点 
BstNode *GetNode(int data){
	BstNode * temp = new BstNode();
	temp->data = data;
	temp->left = temp->right = NULL;
	return temp;
} 

// 递归实现插入 
BstNode* Insert( BstNode * root ,int data){
	// 树为空,设置根节点
	if(root == NULL){
		root = GetNode(data);
	} 
	// 树不空,小于则 插左边
	// 树不空,大于 插右边 
	else if(data <= root->data) {
		root->left = Insert(root->left ,data);
	}
	else if(data >= root->data) {
		root->right= Insert(root->right ,data);
	}
	return root;    // root 是局部变量 
}


// 前序遍历 
void PreOrder(BstNode *root){
	// 边界
	if(root == NULL) {
		return ;
	} 
	cout << root->data<< " ";
	PreOrder(root->left);
	PreOrder(root->right ); 
} 
//中序遍历
void InOrder(BstNode *root){
	// 边界
	if(root == NULL) {
		return ;
	} 
	PreOrder(root->left);
	cout << root->data<< " ";
	PreOrder(root->right ); 
} 
//后序遍历
void PostOrder(BstNode *root){
	// 边界
	if(root == NULL) {
		return ;
	} 
	PreOrder(root->left);
	PreOrder(root->right ); 
	cout << root->data<< " ";
} 

int main(){
   
   BstNode *root =NULL;  // 局部变量 
   root = Insert(root ,15);
   root = Insert(root ,23);
   root = Insert(root ,20);
   root = Insert(root ,8);
   root = Insert(root ,12);
   root = Insert(root ,2); 
   cout << " PreOrder is :";
    PreOrder(root);
    cout << endl; 
   cout << " InOrder is :";
   InOrder(root) ;
   cout << endl;
   cout << " PostOrder is :";
   PostOrder(root) ;
    
    
} 

在这里插入图片描述

6、图

概念

节点之间有关系任意方式链接
n个顶点,n-1个边有序对,无序对
有序对无序对
(a,b) != (b,a) 单向连接{a,b} == {b,a} 双向连接
树单向连接网络爬虫
稀疏图邻接矩阵
稠密图邻接表

有向图–强连接–从任意一个节点到另一个节点都有边–市内交通网络

邻接表

邻接矩阵

  • 7
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值