C++ 类模版---带表头的单向循环链表模版类

一、带表头结点的单向链表如下:

结构:表头无数据,或者说是垃圾数据,表头结点在整个链表中起到领头的作用,最后的指针指向了NULL指针,我们可以对其进行的操作会更加的简便,比如说在遍历链表的时候,可以不用像没有表头结点链表那样考虑头结点是不是空,在删除和中间插入的时候都给编码人员带来了方便。

二、带表头的单向循环链表

是单向链表的进一步改进方式,链表尾指针重新指向了表头;在删除和插入的时候可以不用考虑尾指针是否为空,因为他们的结构是循环的,为它操作的代码量可以更为精简。

三、本例采用带表头的单向循环链表

并使用C++模板类实现链表的增、删、改、查和排序,因为是循环链表,所以不存在逆置(Reverse)的说法,无法让一个有数据的尾结点代替垃圾值的表头结点, 可能是可以,就是把表头结点排开,让后面的所有结点进行逆转,最后表头结点指向的是原来的尾结点。

Link.h

类模版的声明和实现尽量放在一个文件中,在多文件编程中,定义和声明放在不同文件中可能会引发意想不到的结果。

/*****************************************************
copyright (C), 2019-2020, Lighting Studio. Co.,     Ltd. 
File name:
Author:xozofunny    Version:0.1    Date: 
Description:
Funcion List: 
*****************************************************/
#ifndef _LINK_H_
#define _LINK_H_
#include <iostream>
using namespace std;

/*****************************************************
以后创建新结点就是实例化这个类
*****************************************************/
template <class T>
class Node{
public:
    T data;
    Node<T> *next;
};

/****************************************************
用来完成链表的基本操作
****************************************************/
template <class T>
class List : public Node<T>{//继承结点类使其拥有相应权限
protected:
    Node<T> *head;//链表头结点
    Node<T> *new_node;//链表新结点
    //Node<T> *next;//链表指针域
    int count;//记录结点的个数(不算表头结点)

public:
    List();//构造1--创建链表基类型
    List(const T i);//构造2--給当前链表赋值一次
    //List(const List& obj);//拷贝构造
    void Create_Space(Node<T> **new_node);//封装new分配
    bool Is_Empty();//判断链表是否已清空,一般不会清空
    bool Insert_Tail(int cont);
    bool Delete_Node(const T& loc);
    void Sort_Link(void);//链表排序
    //void Reverse_Link(void);//链表转置

    double Get_Rand(int Min, int Max);//获取一个随机的浮点数
	
    //全局重载输出运算符,用来输出整个链表
    //因为友元函数是类外函数,所以得另外定义一个函数模板
    template <typename U>
    friend ostream& operator<<(ostream &out, List<U>& obj);

    bool Clear();//清空链表,但保持其结构    
    ~List();//析构,释放链表
};


/**************************************************
功能:封装new分配函数
入参:新结点二级地址
规则:至少要为结点分配一次,一直不成功则仅分配十次
C++没有二级引用,只有二级指针
**************************************************/
template <class T>
void List<T>::Create_Space(Node<T> **new_node)
{
	int count = 10;
	do
	{
		*new_node = new Node<T>;
		count--;
	}
	while (*new_node == NULL && count);	
}

/*************************************************
功能:判断链表是否为空,(因为我是带表头的)
空表示基类型仍然存在,但不带任何数据
入参:无
返回值:bool
*************************************************/
template <class T>
bool List<T>::Is_Empty()
{
	if(head->next == head)
	{
		//cout<<"List was Empty!"<<endl;
		return 1;
	}
	else
		return 0;
}

/*************************************************
默认构造创建链表基类型,并创建表头结点
且为循环链表
*************************************************/
template <class T>
List<T>::List()
{
    cout<<"Default constructor was called"<<endl;
	Create_Space(&head);//当前对象的二级地址
	head->next = head;
	count = 0;
}

/***************************************************
功能:重载构造函数,为当前链表主动添加一个试水值
主调方:无
被调方:创建对象的时候
入参:一个模版类型的值
返回值:无
**************************************************/
template <class T>
List<T>::List(const T i)
{
    cout<<"Costom constructor was called"<<endl;
	Create_Space(&head);
	Create_Space(&new_node);
	head->next = new_node;
	new_node->data = i;
	new_node->next = head;

	count = 1;
}

/*****************************************************
全局函数用于生成指定的随机数可以是整形,也可以是浮点型
*****************************************************/
template <class T>
double List<T>::Get_Rand(int Min, int Max)
{
	//计算 0,1之间的随机小数,得到的值域近似为(0,1),两个数没有它义,只是为了让其精度高一点
	double m1=(double)(rand()%101)/101;
	Min++;//将 区间变为(min+1,max),
	double m2=(double)((rand()%(Max-Min+1))+Min);//计算 min+1,max 之间的随机整数,得到的值域为[min+1,max]
	m2=m2-1;//令值域为[min,max-1]
	return m1+m2;//返回值域为(min,max),为所求随机浮点数
}

/*****************************************************
函数模版用于排序,排序方法---冒泡
返回值:无(带表头的模板类)
入参:无
*****************************************************/
template <class T>//链表插(mao)入(pao)排序
void List<T>::Sort_Link(void)
{
	T tmp;
	Node<T> *p;
	p = head->next;	
#if 0	
	while(p != head && i < count)
	{	
		j = i - 1;
		tmp = p->data;//偏移一个结点的距离
		q = p;
		p = p->next;
		
		while(j >= 0 && q->data > tmp)
		{
			q->next->data = q->data;
			j--;
			q -= seek;
		}
		if(j != i - 1)
		{
			q->next->data = tmp;
		}
		i++;
	}
 #endif
 
	for(int i = 0; i < count -1; i++)
	{
		p = head->next;
		int isSorted = 1;
		for(int j = 0; j < count - 1 - i; j++)
		{
			if(p->data > p->next->data)
			{
				tmp = p->data;
				p->data = p->next->data;
				p->next->data = tmp;
				isSorted = 0;
			}
			p = p->next;
		}
		if(isSorted) break;
	}
}

/*****************************************************
删除某一单链循环表的结点
返回值:bool
入参:欲删除的位置
*****************************************************/
template <class T>
bool List<T>::Delete_Node(const T& loc)
{
	int t = count;
	if(Is_Empty()){
		cout<<"The Link was Empty!"<<endl;
		return 0;
	}
	else{
		Node<T> *p,*q;
		p = q = head->next;
		while(p->next != head)
		{
			if(p->next->data == loc)
			{
				q = p->next;
				p->next = q->next;
				delete q;
				t--;count--;
				break;
			}
			p = p->next;
		}
	}
	if(t == count)
		return 1;
	else
		return 0;
}

/**************************************************
功能:为链表进行尾插工作
入参:描述创建的结点个数
返回值:bool
*************************************************/
template <class T>
bool List<T>::Insert_Tail(int cont)
{
	Node<T> *p;
	T j = 0;
	if(Is_Empty())//如果为空
	{
		p = head->next;
		for(int i = 0; i < cont; i++)
		{
			Create_Space(&new_node);//先创建结点
			j = (T)Get_Rand(1, 10);
			cout<<"You will create rand number:"<<j<<" for new_node value"<<endl;
			new_node->data = j;//生成1-10的随机数
			
			p->next = new_node;
			new_node->next = head;
			p = p->next;
			count++;
		}
	}
	else//不为空,先便历至空
	{
		p = head->next;
		while(p->next != head)
		{
			p = p->next;
		}
		for(int i = 0; i < cont; i++)
		{
			Create_Space(&new_node);//先创建结点
			j = (T)Get_Rand(1, 10);
			cout<<"You will create rand number:"<<j<<" for new_node value"<<endl;
			new_node->data = j;
			p->next = new_node;
			new_node->next = head;
			p = p->next;
			count++;
		}
	}
	if(Is_Empty())
	{
		cout<<"Insert fail"<<endl;
		return 1;
	}
	else{
		cout<<"Insert success"<<endl;
		return 0;
	}
}


/*****************************************************
重载运算符<<将链表作为对象输出整个链表数据
因为友元函数是类外函数,所以得另外定义一个函数模板
******************************************************/
template <typename U>
ostream& operator<<(ostream& out, List<U>& obj)
{
	Node<U> *p = obj.head->next;
	//int i = 1;
	if(obj.Is_Empty())
    {
		out<<"The Link was Empty!"<<endl;
    }
	else{
		out<<"You have "<<obj.count<<" Node in there"<<endl;;
        out<<"Link head->";
		while(p != obj.head)
		{
			out<</*i<<"st:"<<*/p->data<<"->";
			p = p->next;
			//i++;
		}
        cout<<"NULL";
	}

	return out;
}

/***********************************************
函数名:Clear()
主调方:无
被调方:对象
功能:清空链表,但保留其逻辑结构
入参:无
返回值:bool类型
**********************************************/
template <class T>
bool List<T>::Clear()
{
	Node<T> *p;
	
	if(!Is_Empty())
	{
		while(head->next != head)
		{
			p = head->next;
			head->next = p->next;
			delete p;
		}
		if(head->next == head)
			return 1;
		else
			return 0;
	}
	return 0;
}

/*******************************************
功能: 析构函数,用于释放链表 
主调方:清空链表Clear()
被调方:对象消亡时主动调用
入参:无
返回值:无
******************************************/
template <class T>
List<T>::~List()
{
	Node<T> *p;

	Clear();
	p = head;
	head = NULL;
	delete p;
	
	cout<<"Destructor was called successfully!"<<endl;
}

#endif

main.cpp

#include "link.h"



int main()

{

    srand((unsigned)time(NULL));//seed
    List<float> obj;

    obj.Insert_Tail(10);

    cout<<obj<<endl;

    cout<<"- - - - - - - - - - - - - - Sort Link - - - - - - - - - - - - - - - -"<<endl;

    obj.Sort_Link();

    cout<<obj<<endl;

    List<int> *pobj = new List<int>(5);

    pobj->Insert_Tail(12);

    cout<<*pobj<<endl;

    cout<<"- - - - - - - - - - - - - - Sort Link - - - - - - - - - - - - - - - -"<<endl;

    pobj->Sort_Link();

    cout<<*pobj<<endl;

    cout<<"- - - - - - - - - - - - - - Delete Node - - - - - - - - - - - - - - -"<<endl;

    int loc; cout<<"input your data>>"<<endl;

    cin>>loc; pobj->Delete_Node(loc);

    cout<<*pobj<<endl;


    delete pobj;

    return 0;
}

makefile:

.PHONY : clean
cc = g++
target = Link
CPPFLAGS = -I ./
CFLAGS = -Wall -g
obj = main.o 
$(target):$(obj)
    $(cc) -o $@ $^
%.o:%.cpp
    $(cc) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
clean:
    rm -f $(obj)
    rm -i $(target)

编译,运行:

 最后析构函数用于释放链表。。


233

 

 

 

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值