CDay08 链表

回顾:

结构体占据的内存并非成员变量的简单加和,为了点这个智能指针寻址方便,结构体分配内存时有:

对齐:相邻两个成员变量,参照占据内存大的分配内存

补齐:

结构体指针:指向一个结构体的指针


数组>>优化>>动态数组>>队列和栈:保存多个相同类型的数据;

增:在末尾添加速度快,在头部添加速度慢,因为在头部添加需要将数组中所有的数据往后挪一位

删:效率不高,因为需要挪数据。

改:

查:快,只要首地址+偏移量解引用就可以了

链表:插入删除效率高(只需要改变钩子钩的位置就可以了,不需要挪),但是查找效率低(因为查找需要顺藤摸瓜逐步查)

节点:链表的组成部分

内存泄漏:只申请内存但不及时释放内存。

#include <cstdio>;
#include <cstdlib>;
#include <iostream>;
using namespace std; 
//1.制作节点类型
struct node{
	int data;//数据
	struct node* next;//指针 
};

//2.在堆内存中创建一个节点并返回节点首地址
node* CreateNode(int data); 
//3.尾插法
bool addNode(node* head,int data);
//4.遍历链表的函数 
void travel(node* p){
	while(p!=NULL){
		cout<<p->data<<endl;
		p=p->next;
	}
	return;
} 
//5.查找链表中第n个节点,并返回节点首地址,如果找不到返回空
node* getPos(node* head,int n); 
//作业:查找链表中第一个值为xxx的节点,并返回节点首地址,如果找不到返回空
//6.插入一个节点到链表中第n个节点后,新节点数据为data,返回插入是否成功
bool insertNode(node* head,int n,int data);  
//7.删除链表中第n个节点
bool deleteNode(node* head,int n); 
 
node* getPosByData(node* head,int data); 
int main(){
	node* head=CreateNode(123);
	addNode(head,4546);
	addNode(head,678);
	addNode(head,488);
	addNode(head,4566);
	cout<<"插入前的list:"<<endl; 
	travel(head);
	node* test=getPos(head,7);
	cout<<"dizhi:"<<test<<endl; 
	//cout<<"查找到的:"<<test->data<<endl; 
	node* _test=getPosByData(head,488);
	cout<<"查找到的:"<<_test->data<<endl; 
	node* itest=getPosByData(head,588);
//	cout<<"查找到的:"<<itest->data<<endl;
    insertNode(head,5,8888);
    cout<<"插入后的list:"<<endl;
	travel(head); 
	deleteNode(head,6);
	cout<<"删除后的list:"<<endl;
	travel(head); 
	
	return 0;
}
node* CreateNode(int data){
	node* pNew=(node*)malloc(sizeof(node));
	pNew->data=data;
	pNew->next=NULL;
	return pNew;
}
bool addNode(node* head,int data){
    //0.排除意外 
	 if(head==NULL) return false; 
	//1.找到要插入的节点
	/*low逼写法 
	 while(1){
	 	if(head->next==NULL) break;//head指向最后一个节点,找到了 
		head=head->next;     //head保存下一个节点首地址  
	 }*/
	 //功能实现了一定要优化代码,一个对自己要求高的程序员,一定想着把自己的代码写得更好。 
	 //就像写文章,先记流水账,然后提炼成散文,然后提炼成一首诗。 
	 //优雅写法 
	 while(head->next) head=head->next;
	//2.把新节点连接到要插入的节点后 
	head->next=CreateNode(data);
	return true;
}
//5.查找链表中第n个节点,并返回节点首地址,如果找不到返回空
node* getPos(node* head,int n){
	if(n<=0) return NULL;//防御性编程,一个好的产品都是把用户想的特别特别傻的。 
	int i;
	for(i=0;i<(n-1);i++){
	  if(head==NULL) return NULL;//注意这一步 
	   head=head->next;	
	}
	return head;
}

//作业:查找链表中第一个值为xxx的节点,并返回节点首地址,如果找不到返回空
node* getPosByData(node* head,int data){
	while(head){
		if(head->data==data) return head;
		head=head->next; 
	}
	cout<<"can not find"<<endl;
	return NULL;
}
//6.插入一个节点到链表中第n个节点后,新节点数据为data,返回插入是否成功
//如果只能实现功能,那么只是一个码农的水准,如果你能够自己设计函数,那么就到了设计师的水准。
//如果你能够把整个项目拆分成很多个函数,拆分成很多个类,那么你就是总工程师的水准。
//我们在学习的时候绝对不能以实现功能为最终目的,我们还必须往设计的方面想想。 
bool insertNode(node* head,int n,int data){
	
	node* pTemp=getPos(head,n);//获取第n个节点的地址
	node* pTemp2=getPos(head,n+1);//获取第n+1个节点的地址 
	node* _head=NULL;
	if(pTemp!=NULL) {
	_head=CreateNode(data);//如果能找到第n个节点的首地址,那么创建新节点
	pTemp->next=_head;//让第n个节点的next指向新节点 
    }
	else return false; 
	
	if(pTemp2){
		_head->next=pTemp2;//让新节点的next指向原来的n+1个节点 	
	} 
	else _head->next=NULL;
	return true; 

}
//7.删除链表中第n个节点
bool deleteNode(node* head,int n){
	if(head==NULL || n<1) return false;
	node* pTemp1=getPos(head,n-1);//获取第n-1个节点的地址 
	node* pTemp2=getPos(head,n);//获取第n个节点的地址
	node* pTemp3=getPos(head,n+1);//获取第n+1个节点的地址
	if(pTemp2==NULL) return false;
	pTemp1->next=pTemp3;
	free(pTemp2);
	pTemp2->next=NULL;
	pTemp2->data=0; 
	return true;
	 
} 

注意,deleteNode函数需要重写,因为这个函数不能删除第一个节点

待重写,有问题的代码:

#include <iostream>
#include <cstdlib>
using namespace std;
//1.制作节点类型
template<typename F>
class node{
	F data;//数据 
	node* next;//指针 
public:
	//3创建一个节点并返回节点首地址 
	node* CreateNode(F data); 
	//尾插法:插入节点到链表的尾部 
	bool addNode(F data);
	bool addNode(node* head,F data);
	void travel(node* p);
}; 
//2第一个节点的首地址能代表整个链表 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

// 

int main(int argc, char** argv) {
	node<int>* pList=NULL;//第一个节点的首地址
	//4.制造链表头节点
	node<int> head;
	pList=head.CreateNode(123);
	//5.尾插法:插入节点到链表的尾部 
	//head.addNode(345);
	//head.addNode(789);
	head.addNode(pList,345);
	head.addNode(pList,567);
	
	
	head.travel(pList);
	return 0;
}
//创建一个节点并返回节点首地址
template<typename F> 
node<F>* node<F>::CreateNode(F data){
	//开辟内存
	node<F>* pNew=(node<F>*)malloc(sizeof(node<F>)); //malloc开辟的内存段在堆内存中,堆内存不会因为函数结束而释放,只能被手动free,所以可以返回其首地址。
//函数不可以返回函数内部定义的局部变量的地址,因为局部变量占据的内存在函数运行结束之后就自动释放了,返回这种地址没有意义 
	//初始化 
	pNew->data=data;
	pNew->next=NULL;
	// 返回 
	return pNew;
}
//尾插法:插入节点到链表的尾部 
template<typename F> 
bool node<F>::addNode(F data){
    node<F>* pTemp=this;
	//找到要插入的节点 
	while(1){
		if(pTemp->next==NULL) break;//head指向最后一个节点,找到了 
		pTemp=pTemp->next;  //head保存下一个节点首地址  
	} 
	//把新节点连接到要插入节点后 
	node<F> n;
	pTemp->next=n.CreateNode(data); 
	return true;
}
template<typename F> 
bool node<F>::addNode(node<F>* head,F data){
    //0.排除意外 
	 if(head==NULL) return false; 
	//1.找到要插入的节点
	 while(1){
	 	if(head->next==NULL) break;//head指向最后一个节点,找到了 
		head=head->next;     //head保存下一个节点首地址  
	 } 
	//2.把新节点连接到要插入的节点后 
	node<F> n;
	head->next=n.CreateNode(data);
	return true;
}
template<typename F>
void node<F>::travel(node* p){
	while(p!=NULL){
		cout<<p->data<<endl;
		p=p->next;
	}
} 

猜你喜欢

转载自blog.csdn.net/weixin_43415644/article/details/88632825
今日推荐