自己写链表结构体和二叉树

上次商汤科技面试问到删除链表倒数第N个节点的题目,题目本身不难,但是需要自己写链表的输入,结构体创建等,下面附上两种方法,其实是一样的哈哈,细微区别,考虑到了链表可能输入长度是0的情况!
Case1:自定义输入链表元素,然后实现功能,链表元素可以不输入就是空链表
代码1:val赋值和链表创建分开:

//删除倒数第N个链表j节点自己写
//	head->next=new Listnode();这样是不行的,因为next是空节点,没有资格进行操作,因为没有val 
#include<bits/stdc++.h>
using namespace std;
struct ListNode{
	int val;
	ListNode*next;
	ListNode():val(0),next(nullptr){}
	ListNode(int x):val(x),next(nullptr){}		
}; 

ListNode* DeleteNode(ListNode* head,int n); //函数声明 
int main(){
	cout<<"Please enter the length of the list: ";
	int M; cin>>M;
	vector<int>nums(M);
	ListNode* head=new ListNode();
	ListNode* temp=head;
	if(M==0){
		cout<<"nullptr";
		return 0;
	}
		
	for(int i=0;i<M;i++){
    	cin>>nums[i];
		temp->next=new ListNode(nums[i]); //反正注意把,只有new的元素可以对next进行操作,操作也是给new!! 除非索引到已经建立的链表就Listnode*temp=head; 
		temp=temp->next;
		temp->next=nullptr;//稳妥起见		
	}
	head=head->next;
	
	//调用函数
	cout<<"Please delete the last n node: ";
	int n; cin>>n; 
	ListNode* Head=DeleteNode(head,n);
	if(Head==nullptr)
		cout<<"This is nullptr"; 
	while(Head!=nullptr){
		cout<<Head->val<<" ";
		Head=Head->next;
	}
	return 0;		
}
///leetcode函数 
ListNode* DeleteNode(ListNode* head,int n){
	if(head==nullptr)
		return head; 
	ListNode* dummy = new ListNode(0);
	dummy->next=head;
	ListNode* cur = dummy;
	int length=0;
	while(head){
		length++;
		head=head->next;	
	}
        
	for (int i = 1; i < length - n + 1; ++i) {
        	cur = cur->next;
    }
    cur->next = cur->next->next;
    ListNode* ans = dummy->next;
    delete dummy;
    return ans;		
}


代码2:val和链表创建合在一起:

//删除倒数第N个链表j节点自己写
//	head->next=new Listnode();这样是不行的,因为next是空节点,没有资格进行操作,因为没有val 
#include<bits/stdc++.h>
using namespace std;
struct ListNode{
	int val;
	ListNode*next;
	ListNode():val(0),next(nullptr){}
	ListNode(int x):val(x),next(nullptr){}		
}; 

ListNode* DeleteNode(ListNode* head,int n); //函数声明 
int main(){
	cout<<"Please enter the length of the list: ";
	int M; cin>>M;
	vector<int>nums(M);
	ListNode* head=new ListNode(); //没有赋值就是空结点 
	ListNode* temp=head;
	for(int i=0;i<M;i++){
    	cin>>nums[i];
    	temp->val=nums[i];
    	if(i!=M-1){
    		temp->next=new ListNode(); //反正注意把,只有new的元素可以对next进行操作,操作也是给new!! 除非索引到已经建立的链表就Listnode*temp=head; 链表这种必须分配空间就是反正
			temp=temp->next; 	
		}
		temp->next=nullptr;//稳妥起见		
	}
	
	//调用函数
	cout<<"Please delete the last n node: ";
	int n; cin>>n; 
	ListNode* Head=DeleteNode(head,n);
	if(Head==nullptr)
		cout<<"This is nullptr"; 
	while(Head!=nullptr){
		cout<<Head->val<<" ";
		Head=Head->next;
	}
	return 0;		
}
///leetcode函数 
ListNode* DeleteNode(ListNode* head,int n){
	if(head==nullptr)
		return head;
	ListNode* dummy = new ListNode(0);
	dummy->next=head;
	ListNode* cur = dummy;
	int length=0;
	while(head){
		length++;
		head=head->next;	
	}
        
	for (int i = 1; i < length - n + 1; ++i) {
        	cur = cur->next;
    }
    cur->next = cur->next->next;
    ListNode* ans = dummy->next;
    delete dummy;
    return ans;		
}

下面附上删除正数第N个节点的主干程序:

如输入1->2->3->3->4->5,删除第3个节点;
ListNode * deleteNodes(ListNode* head,int& index)
{
    if(head== nullptr)
    {
        return nullptr;
    }
    ListNode* dumpy=new ListNode();
    dumpy->next=head;
    ListNode* cur=head;
    ListNode* prev=dumpy;
    int count=1;
    while(cur!= nullptr)
    {
        if(count==index)
        {
            prev->next=cur->next;
            break;
        }
        prev=cur;
        cur=cur->next;
        count++;

    }
    return dumpy->next;
}

————————————————————————————————————————
Case2:根据输入的数组来创建二叉树,然后对二叉树操作Leetcode题目实现功能:
除了链表,二叉树的输入也是题目可能会考到的,下面举个简单的二叉树问题来分析代码:

代码1: 层序遍历输入数组创建二叉树,层序遍历输出,这里输出可以前中后序就不展开了。这里的情况针对输入是完全二叉树

//程序功能:输入一组数据是二叉树的层序遍历,要求根据数据创建二叉树,然后用层序遍历来输出二叉树 
#include<string>
#include<sstream>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

struct TreeNode{
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode():val(0),left(NULL),right(NULL){} //这样允许我们可以使用 new TreeNode 或者 new TreeNode() 
	TreeNode(int x):val(x),left(NULL),right(NULL){} //这里就简单这么赋值把 
};

TreeNode* creatBinTree(vector<int> & arr) ;
void printBinTree_bfs(TreeNode* head); //声明下二叉树输出函数 
int Final_Task(TreeNode* head);
int main() {
	vector<int> a;
	cout<<"Please enter the numbers: "<<endl;
	string str; getline(cin,str);
	stringstream ss(str); string temp;
 	while(getline(ss,temp,' '))
    {
 		a.push_back(stoi(temp));
    }

	TreeNode* head = creatBinTree(a); //注意到这样就行了,虽然里面是创建了形参,但是我最终给他return出来了两个地址对上了地址的改变还是存在的!!! 
	printBinTree_bfs(head);
	//int res=Final_Task(head); //比如是int形式的输出
	//cout<<res; 
}


//按照层序遍历构造二叉树--二叉树构造程序 
TreeNode* creatBinTree(vector<int> & arr) { 
 queue<TreeNode*> q;
 //如果层序序列为空,返回空树
 if (arr.empty()) {
  return nullptr;
 }
 
 TreeNode* head =new TreeNode; //创建头节点  注意到结构体的赋值用new一般是针对指针式样结构体 如链表和树这种 
 head->val = arr[0];  //存放数组首元素
 q.push(head); //入队
 
 TreeNode* temp; //工具人temp 
 int i = 1;
 while (!q.empty()) {
  temp = q.front();  //取出头节点,准备给它安排左右孩子
  q.pop(); //头节点出队,每一次新的循环,都让头出队
  
  //先弄左孩子
  //i只要不超过数组的有效长度,就有左孩子从0开始计数,0已经赋值就1了 
  if (i < arr.size()) {
   temp->left = new TreeNode(); //或者 new TreeNode 
   temp->left->val = arr[i];
   q.push(temp->left);  //左孩子入队
   i++; //数组后移
  }
  else {
   temp->left = nullptr;
  }
  
  //再弄右孩子
  if (i < arr.size()) {
   temp->right = new TreeNode();
   temp->right->val = arr[i];
   q.push(temp->right);  //右孩子入队
   i++;  //数组后移
  }
  else {
   temp->right = nullptr;
  }
 }
 return head;  //最后队列为空就出while,返回头节点
}

//层序遍历二叉树
void printBinTree_bfs(TreeNode* head) {
 queue<TreeNode*> q;
 
 //树为空
 if (head == nullptr) {
  cout << "TreeNode is empty!" <<endl;
  return;
 }
 
 //头节点入队
 q.push(head);
 TreeNode* b; //工具人b 
 while (!q.empty()) {
  b = q.front();  //拿到队头,队头出队
  q.pop();
  cout <<b->val<< endl;  //打印对头的数据
  
  //对头的左孩子存在就入队
  if (b->left) {
   q.push(b->left);
  }
  
  //对头的右孩子存在就入队
  if (b->right) {
   q.push(b->right);
  }
 }
}




///自己的程序
/*
Final_Task(TreeNode*head){
	//比如输出二叉树的最大深度 
}

*/ 

代码2:那有人会问,上面的情况是 针对完全二叉树,如果输入的数据中有null怎么办啊 可以在输入时候做微小的改动,这里是层序遍历的输入元素,可以存在nullptr,然后层序输出二叉树元素

//程序功能:输入一组数据是二叉树的层序遍历,要求根据数据创建二叉树,然后用层序遍历来输出二叉树,支持输入的元素是逗号隔开存在nullptr
#include<string>
#include<cstring>
#include<sstream>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

struct TreeNode{
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode():val(0),left(NULL),right(NULL){} //这样允许我们可以使用 new TreeNode 或者 new TreeNode() 
	TreeNode(int x):val(x),left(NULL),right(NULL){} //这里就简单这么赋值把 
};

TreeNode* creatBinTree(vector<string> & arr) ;
void printBinTree_bfs(TreeNode* head); //声明下二叉树输出函数 
int Final_Task(TreeNode* head);
int main() {
	vector<string> a;
	cout<<"Please enter the numbers: "<<endl;
	string str; getline(cin,str);
	stringstream ss(str); string temp;
 	while(getline(ss,temp,' '))
    {
 		a.push_back(temp);
    }

	TreeNode* head = creatBinTree(a); //注意到这样就行了,虽然里面是创建了形参,但是我最终给他return出来了两个地址对上了地址的改变还是存在的!!! 
	printBinTree_bfs(head);
	//int res=Final_Task(head); //比如是int形式的输出
	//cout<<res; 
}


//子程序1:-------------------------按照层序遍历构造二叉树--二叉树构造程序 
TreeNode* creatBinTree(vector<string> & arr) { 
 queue<TreeNode*> q;
 if (arr.empty()) {
  return nullptr;
 }
 
 TreeNode* head =new TreeNode; //创建头节点  注意到结构体的赋值用new一般是针对指针式样结构体 如链表和树这种 
 head->val = stoi(arr[0]);  
 q.push(head); 
 
 TreeNode* temp; //工具人temp 
 int i = 1;
 while (!q.empty()) {
  temp = q.front();  
  q.pop(); 
  
  //先弄左孩子
  //i只要不超过数组的有效长度,就有左孩子从0开始计数,0已经赋值就1了 
  if (i < arr.size()) {
  	if(arr[i]=="nullptr")
   		temp->left=nullptr;
    else{
   		temp->left = new TreeNode(); //或者 new TreeNode 
   		temp->left->val = stoi(arr[i]);
   		q.push(temp->left);  //左孩子入队
	   }
	i++; //数组后移 
}
  else 
   temp->left = nullptr;
  
  //再弄右孩子
  if (i < arr.size()) {
  	if(arr[i]=="nullptr")
  		temp->right=nullptr;
  	else{
  		temp->right = new TreeNode();
   		temp->right->val = stoi(arr[i]);
   		q.push(temp->right);  //右孩子入队
	  }
	i++;  //数组后移	
  }
  else 
   temp->right = nullptr; 
 }
 return head;  //最后队列为空就出while,返回头节点
}

//子程序2:------------------------层序遍历输出二叉树
void printBinTree_bfs(TreeNode* head) {
 queue<TreeNode*> q;
 
 //树为空
 if (head == nullptr) {
  cout << "TreeNode is empty!" <<endl;
  return;
 }
 
 //头节点入队
 q.push(head);
 TreeNode* b; //工具人b 
 while (!q.empty()) {
  b = q.front();  //拿到队头,队头出队
  q.pop();
  cout <<b->val<< endl;  //打印对头的数据
  
  //对头的左孩子存在就入队
  if (b->left) {
   q.push(b->left);
  }
  
  //对头的右孩子存在就入队
  if (b->right) {
   q.push(b->right);
  }
 }
}




///自己的程序
/*
Final_Task(TreeNode*head){
	//比如输出二叉树的最大深度 
}

*/ 

————————————————————————————————————————
Case3:
有时候我们的输入不是层序遍历,比如是前序遍历,或者后序中序遍历。这里原理是一样的。我们取前序遍历来展开。即,输入的元素比如1 2 3 4是二叉树的前序遍历顺序,要求我们创建对应二叉树实现功能,如何创建二叉树呢:
下面的是前序遍历构建二叉树的子程序! 注意到我们的index作为全局变量初始值给1,因为遇到空节点的时候会自动return,这样就不会说出不来了。注意就是当我们是right或者left指向的时候其实宏观是这个根节点的位置!!这个是递归的想法

//子程序1:-------------------------按照前序构造二叉树--二叉树构造程序 
TreeNode* creatBinTree(vector<string> & arr) { 
    if(arr.size()==0)
    	return nullptr;
 
    string value=arr[index];
    index++;
	if (value =="nullptr") {
		return nullptr;
	}
	TreeNode* head = new TreeNode(stoi(value));//如果不为空则创建该节点,同时递归进行左节点与右节点的创建 
	head->left = creatBinTree(arr);
	head->right= creatBinTree(arr);
	return head;
	
}

或者,如何实现后续遍历输入呢:
对于1 2 3然后下面4个空节点的二叉树,我们按照后序遍历输入:
X X 2 X X 3 1,层序遍历输出应该是1 2 3
下面附上代码,其思路是按照根 右 左,和后续遍历的顺序相反来构建二叉树,前提是对输入数组进行一个反转。这样就能和前序遍历类似来构造函数了
这也是考虑到了中序或者后续遍历开头就是nullptr,不好返回

//子程序1:-------------------------按照后续遍历构造二叉树--二叉树构造程序 
TreeNode* creatBinTree(vector<string> & arr) { 
    if(arr.size()==0)
    	return nullptr;
 
    string value=arr[index];
    index++;
	if (value =="nullptr") {
		return nullptr;
	}
	TreeNode* head = new TreeNode(stoi(value));
	
	head->right= creatBinTree(arr);  //注意到我这边用了 根、右、左的顺序。输出的是相反的 
	head->left = creatBinTree(arr);
	
	return head;
	
}

中序遍历不能得到有效解:
可以看到同样的输入序列有不同的二叉树~
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值