用c++实现数据结构中的单链表

本篇内容中的代码注释皆为本人的理解,如果有误,请指正!

本篇内容参考自:http://www.nowamagic.net/librarys/veda/detail/1803

Link.h:

#pragma once
#include <iostream>
#include <string>
using namespace std;
struct node//创建一个结构体
{
	string data;
   struct  node *next;
};
class Link
{
public:
	Link(void);//构造函数,用于初始化
	void insertIndex(string _data,int index);//插入指定位置
	void insertFirst(string _data);//在头部插入
	void insertLast(string _data);//在末尾插入
	void delIndex(int index);//删除指定位置
	void delFirst();//删除头部
	void delLast();//删除尾部
	void delAll();//删除全部
	void findIndex(int index);//查找指定位置的数据
	void findData(string _data);//查找指定数据的位置
	void print()const;//打印
	void getNodeFromBack(int n);//获取单链表倒数第n个结点的值
	void reverse();
	int getLen()const;//获取链表长度
	~Link(void);
private:
	struct node *head;//定义一个头节点head
	int len;//链表的长度
};

Link.cpp:

#include "Link.h"
//用于初始化
Link::Link(void)
{
	head = new node;//给head开辟空间,注:(.h)中只定义head,但是没有开辟空间,
	head->next= NULL;//使头结点指向下一结点的指针域置空
	head->data="head";//头结点的数据域存值
	len = 0;//初始值为0,不算头结点
}

//插入指定位置
void Link::insertIndex(string _data,int index){
	if(index <0)//判断输入的下标是否合法
	{
		cout<<"index error"<<endl;
		return ;//一般void不能返回一个值,即不能return 一个值.但是这里只是return;故可以使用
	}          
	node *newNode = new node;//创建一个新结点,该结点为待插入的结点
    node *temp =head;//创建一个新结点用来存储头结点
	if(index ==0){//如果插入的下标为0,即要插入到头结点的前面时
		newNode->next=temp;//新结点的指针域指向temp结点
		head = newNode;//把插入的结点设置为头结点,因为头结点永远是在最前面的
		newNode->data = _data;//把要存储的值 赋值到新结点的数据域中
		len++;//长度+1
		return ;
	}
	if(index >0){
		int k =1;//一个比较标记,值为1代表从是第一个结点
		while(k<index && temp !=NULL){//如果比较标记小于要插入的位置 且temp结点不为NULL时,执行循环体
			temp =temp->next;//temp结点指向下一个结点
			++k;//比较标记跟着循环体改变,当不满足k<index关系时,说明已经找到要插入的位置了
		}
		if(temp ==NULL){//如果temp的结点为空,则说明整个链表为空,结点插入不了
			cout<<"NULL"<<endl;
			return ;
		}
		newNode->next = temp->next;//待插入结点的指针域指向temp结点的下一结点
		temp->next = newNode;//temp结点的指针域指向待插入结点
		newNode->data = _data;///把要存储的值 赋值到新结点的数据域中
		len++;//长度+1
	}
}

//头部插入
void Link::insertFirst(string _data){
	if(head ==NULL){//判断当前头结点是否为空,如果为空,则插入不了
		cout<<"head is NULL"<<endl;
		return ;
	}
	node *newNode =new node;//创建一个新结点,该结点为待插入的结点
	newNode->next =head->next;//新结点的指针域指向头结点的下一结点
	head->next = newNode;//头结点的指针域指向新结点
	newNode->data =_data;//把要存储的值 赋值到新结点的数据域中
	len++;//长度+1
}

//末尾插入
void Link::insertLast(string _data){
	node *temp =head;//创建一个新结点用来存储头结点
	while(temp->next !=NULL){//一直循环到链表的末尾,当temp的指针域为空时,代表temp结点为最后一个结点
		temp =temp->next;//temp结点依次往后更替
	}
	node *newNode =new node;//创建一个新结点
	temp->next =newNode;//temp结点的指针域指向新结点  注:这是新结点为最后一个结点
	newNode->next =NULL;//新结点的指针域置空
	newNode->data =_data;//把要存储的值 赋值到新结点的数据域中
	len++;//长度+1
}

//删除指定位置
void Link::delIndex(int index){
	if(index <0){//判断输入的下标是否合法
		cout<<"index error"<<endl;
		return ;
	}
	else if(index ==0){//当下标为0时,代表要删除的是当前头结点
		head = head->next;//把头结点移到下一结点
		len--;//长度-1
	}
	else if(index >0){
		node *temp = head;//创建新结点存储头结点
		int k=1;//一个比较标记,值为1代表从是第一个结点
		while(k<index &&temp!=NULL){//如果比较标记小于要删除的位置 且temp结点不为NULL时,执行循环体
			temp =temp->next;//temp结点指向下一个结点
			k++;//比较标记跟着循环体改变,当不满足k<index关系时,说明已经找到要删除的位置了
		}
		node *p = temp->next;//创建新结点指向temp结点的下一结点
		temp->next = p->next;//temp的指针域指向p的下一结点,即temp的下一个结点的下一个结点
		delete p;//从堆中删除结点
		len--;//长度-1
	  }
}

//删除头部
void Link::delFirst(){
	if(head ==NULL){//判断头结点是否为空
		cout<<"head is NULL"<<endl;
		return ;
	}
	node *temp = head;//创建新结点存储头结点
	head = head->next;//当前头结点指向下一结点
	delete temp;//从堆中删除结点
	len--;//长度-1
}

//删除尾部
void Link::delLast(){
	node *temp =head;//创建新结点存储头结点
	node *newNode=new node;//创建一个新结点
	while(newNode->next!=NULL){//循环一直到最后的结点指针域为空
		temp = temp->next;
		newNode = temp->next;
	}
	temp->next = newNode->next;//temp结点的指针域指向newNode的指针域,即最后一个结点的指针域
	newNode->next=NULL;//newNode的指针域置为空,代表最后一个结点
	delete newNode;//删除结点
	len--;//长度-1
}

//删除全部
void Link::delAll(){
	node *temp ;//创建一个结点
	int k=len;//用来保存当前的长度
	for(int i=0;i<k;i++){//使temp结点从头结点遍历到最后结点,依次删除
		temp =head;
		head=head->next;
		len--;
		delete temp;
	}
}

//查找指定位置的数据
void Link::findIndex(int index){
	if(index>len ||index<0  ){//判断下标是否合法
		cout<<"index error"<<endl;
		return;
	}
	int k=0;//一个标记,从头结点开始
	node *temp =head;//创建新结点存储头结点
	while(k<index && temp!=NULL){//依次循环,直到标记和下标相等,说明找到了要查找的位置
		temp =temp->next;
		++k;
	}
	if(index ==0)cout<<"该位置为头结点,其数据为:"<<temp->data<<endl;
	else cout<<"查找第"<<index<<"个的数据为:"<<temp->data<<endl;
}

//查找指定数据的位置
void Link::findData(string _data){
	node *temp =head;//创建新结点存储头结点
	for(int i=0;i<=len;i++){//循环遍历
		if(temp !=NULL && temp->data ==_data){//当找到数据时,打印输出
			if(i==0) cout<<_data<<"的位置为: 头结点"<<endl;
			else cout<<_data<<"的位置为: "<<i<<endl;
			return ;
		}
		temp =temp->next;//如果没找到 继续循环找下去
	}
	cout<<"没有找到"<<_data<<endl;
}

//获取单链表中倒数第n个结点的值
void Link::getNodeFromBack(int n){//建立两个指针,第一个先走n步,然后第2个指针也开始走,                           
	node *temp =head;            //两个指针步伐(前进速度)一致。当第一个结点走到链表末尾时,
	node *newNode =head;        //第二个节点的位置就是我们需要的倒数第n个节点的值。
	int k=0;
	while(k <n &&temp->next !=NULL){
		k++;
		temp = temp->next;
	}

	if(temp->next ==NULL && k<n-1){
		cout<<"超出链表长度"<<endl;
		return ;
	}
	while(temp !=NULL){
		//查找倒数第N个元素
		temp =temp->next;
		newNode =newNode->next;
	}
	cout<<"倒数第"<<n<<"的值为:"<<newNode->data<<endl;
}

//链表逆序
void Link::reverse(){
	node *p1,*p2,*p3;//创建三个新结点
	p1 =head->next;//p1 结点存储的是第一个结点
	p2 = p1->next;//p2 结点存储的是第二个结点
	p1->next =NULL;//将第一个结点指向的下一结点置空
	while(p2!=NULL){//p2结点为主要操作结点,当p2为空时,说明已经逆序完毕
		p3 =p2->next;//p3结点存储的是p2结点的下一结点
		p2->next =p1;//p2结点指向p1
		p1 = p2;//把逆序过来的结点置为p1
		p2 = p3;//p2结点向后移一位
	}
	head->next =p1;//最后把头结点的下一结点置为最终逆序过来的p1结点即可
	               //(即头结点指向p1,而p1指向后面的结点,形成链表)
}

//打印
void Link::print()const {
	if(head== NULL){//判断头结点是否为空
		cout<<"error"<<endl;
		return ;
	}
	cout<<"len: "<<getLen()<<endl;
	cout<<"头结点的数据为:"<<head->data<<endl;
	node *temp = head->next;//创建新结点存储头结点的下一结点
	for(int i=0;temp !=NULL;i++){//循环遍历输出
		cout<<"第"<<i+1<<"个的数据为:"<<temp->data<<endl;
		temp = temp->next;
	}
	cout<<endl;
}

//获得长度
int Link::getLen()const{
	return len;
}

Link::~Link(void)
{
	node *temp;//定义一个新结点
	for(int i=0;i<=len;i++){//循环遍历,从头结点到最后结点,依次删除
		temp =head;
		head =head->next;
		delete temp;
	//	cout<<"析构"<<endl;
	}
}

main.cpp:

#include <iostream>
#include "Link.h"
using namespace std;
int main()
{
	Link l;

	cout<<"打印*****************"<<endl;
	l.print();


	cout<<"尾部插入******************"<<endl;
	l.insertLast("a");
	l.insertLast("b");
	l.insertLast("c");
	l.insertLast("d");
	l.print();


	cout<<"逆序打印*******************"<<endl;
	l.reverse();
	l.print();


	cout<<"指定位置插入*******************"<<endl;
	l.insertIndex("e",3);
	l.print();


	cout<<"首部插入*******************"<<endl;
	l.insertFirst("f");
	l.print();

	
	cout<<"查找*******************"<<endl;
	l.getNodeFromBack(2);
	l.findData("a");
	l.findData("q");
	l.findIndex(4);
	l.findIndex(9);
	cout<<endl;


	cout<<"删除指定位置*******************"<<endl;
	l.delIndex(0);
	l.print();


	cout<<"删除头部*******************"<<endl;
	l.delFirst();
	l.print();


	cout<<"删除尾部*******************"<<endl;
	l.delLast();
	l.print();


	cout<<"删除全部*******************"<<endl;
	l.delAll();
	l.print();

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值