数据结构线性表单链表描述c++(二)

本例子是《数据结构与算法c++描述》中的线性表中单向链表(singly linked list)

 

单链表原理图:

      first 为头节点  ,由于第一个节点 e1 的指针指向第二个节点 e2, e2 的指针指向e3 ,. . .,最后一个节点链接域为 N U L L (或0 ),故这种结构也被称作链(chain)。

 

单链表定义:

/*
数组结构中的线性表链表样式

对应书中代码:数据结构算法与应用c++描述

程序编写:比卡丘不皮

编写时间:2020年6月30日 17:55:29
*/

#pragma once
#include "all_error.h"
#include <iostream>
using namespace std;

template<class T>
class Chain;  //声明

template<class T>
class ChainIterator; //迭代器


template<class T>
class ChainNode
{
	friend Chain<T>;
	friend ChainIterator<T>;  //因为要访问private
private:
	T data;
	ChainNode<T> * link;
};


template<class T>
class Chain
{
	friend ChainIterator<T>;  //应为要访问private
public:
	Chain() { first = 0; last = first; };//初始化函数
	~Chain();                            //析构函数
	Chain(const Chain<T> & Val);  //复制构造函数
	bool IsEmpty() const { return first == 0; }   //判断是不是空
	int Length()const;                    //链表的长度
	bool Find(int k, T &x) const;         //查找第k可的数据,没有为false
	int Search(const T & x) const;        //查找数据函数
	Chain<T>& Delete(int k, T & x);       //删除某个数据
	Chain<T>& Insert(int k, const T & x); //插入数据
	void Output(ostream & out)const;  // 输出接点数据
    //扩充链表
	void Erase();                   //删除链表
	void Zero() { first = 0; }      //数据first 为0
	Chain<T>& Append(const T & x);  //在最后添加
	Chain<T>& Reverse();   //元素次序的反转  原地的反转
	 //线性表交叉组合 参数一定不是自己的变量
	Chain<T>& Alternate(const Chain<T>& list1, const Chain<T>& list2);
	//有规律(元素从小到大排列)线性表的组合
	Chain<T>& Merge(const Chain<T>& list1, const Chain<T>& list2);
	//链表排序 排序法
	void sort();
	//线性表分割函数  交叉分割
	void Split(Chain<T>& list1, Chain<T>& list2);
	Chain<T> & operator =(const Chain<T>& x); //复制构造函数一定要同时写这个
private:
	ChainNode<T> * first; //记录头指针
	ChainNode<T> * last; //记录尾指针
};


//链表遍历类
template<class T>
class ChainIterator
{
public:
	T * Initialize(const Chain<T> & c)
	{
		location = c.first;
		if (location)
		{
			return &location->data;
		}
		return 0;
	}

	T * Next()
	{
		if (!location)
		{
			return 0;
		}
		location = location->link;
		if (location)
		{
			return &location->data;
		}
		return 0;
	}
private:
	ChainNode<T> *location;
};

 有关  #include "all_error.h" 请看我博客中(1)的写法:

 传送门:https://blog.csdn.net/weixin_42126427/article/details/107013624

首先

template<class T>
class Chain;  //声明

template<class T>
class ChainIterator; //迭代器

声明,在对应类中friend class 是可以在对应链表中访问private变量,所以要声明。

析构函数:

template<class T>
 Chain<T>::~Chain()
{  
	ChainNode<T> * next;
	while (first)
	{
		next = first->link;
		delete first;
		first = next;
	}
}

循环对当前节点删除,而不是只是把first 给delete ,这里一定要这样删除,不然类存泄漏.

Length()函数:

template<class T>
int Chain<T>::Length() const
{
	ChainNode<T> * current = first;
	int len = 0;
	while (current)
	{
		len++;
		current = current->link;
	}
	return len;

}

目的:计算链表的长度,返回长度。

Find(int k, T &x)函数:

template<class T>
 bool Chain<T>::Find(int k, T & x) const
{
	if (k < 1)
	{
		return false;
	}
	ChainNode<T> * current = first;
	int index = 1; //current的索引
	while (index < k && current)
	{
		current = current->link;
		index++;
	}
	if (current)
	{
		x = current->data;
		return true;
	}
	return false;
}

查找第k可的数据,没有为false,有数据,把值赋值给X;

搜索Search(const T & x):

//寻找x, 如果发现x 返回x的地址
//如果不在列表中,返回0
template<class T>
 int Chain<T>::Search(const T & x) const
{
	 ChainNode<T> *current = first;
	 int index = 1;
	 while (current && current->data != x)
	 {
		 current = current->link;
		 index++;
	 }
	 if (current)
	 {
		 return index;
	 }
	return 0;

}

 删除 Delete(int k, T & x)

  删除原理图:

比如要删除第4个,要找到第4个,然后让3连接到5上,然后释放4的节点; 

//把第k个元素取至x,然后从链表中删除第 k个元素
 //如果不存在第 k个元素,则引发异常 OutOfBounds
 template<class T>
 Chain<T>& Chain<T>::Delete(int k, T & x)
 {
	 if (k < 1 || !first)
	 {
		 throw OutOfBounds();
	 }
     // p最终将指向第 k个节点
	 ChainNode<T> * p = first;
	 // 将p移动至第k个元素,并从链表中删除该元素
	 if (k == 1)  //p已经指向第k个元素
	 {
		 first = first->link; //这样就删除了
	 }
	 else
	 {
		 ChainNode<T> * q = first;
		 for (int index = 1; index < k-1 && q; index++)
		 {
			 q = q->link;	 
		 }
		 if (!q || !q->link)
		 {
			 throw OutOfBounds();
		 }
		 //存在第k个元素 删除对应元素
		 p = q->link;
		 if (p == last)
		 {
			 last = q;
		 }
		 q->link = p->link; //两种可能性,p->link为0, 那么 q->link 就是0, 若有下个数据,就连接下个数据		 
	 }
	 x = p->data;
	 delete p;
	 return *this;
 }

输出Output(ostream & out)

template<class T>
 void Chain<T>::Output(ostream & out) const
{
	 ChainNode<T> *current;
	 for (current = first; current; current = current->link)
	 {
		 out << current->data << " ";
	 }
}
 //重载<<
 template<class T>
 ostream & operator <<(ostream & out, const Chain<T> & x)
 {
	 x.Output(out);
	 return out;
 }

 插入Insert(int k, const T & x):

  插入原理图:

当插入为0为在first插入最前,当为k不是0在中间插入 ,OutOfBounds 这些错误在上面的传送门中的头文件中

//在第k个元素之后插入x
 //如果不存在第 k个元素,则引发异常OutOfBounds
 //如果没有足够的空间,则传递 Nomem异常
 template<class T>
Chain<T>& Chain<T>::Insert(int k, const T & x)
 {
	 if (k < 0)
	 {
		 throw OutOfBounds();
	 }
	 //p最终将指向第 k个节点
	 ChainNode<T> * p = first;
	 //将p移动至第k个元素
	 for (int index = 1; index < k && p; index++ )
	 {
		 p = p->link;
	 }
	 //不存在第k个元素
	 if (k > 0 && !p)
	 {
		 throw OutOfBounds();
	 }
	 //插入
	 ChainNode<T> * y = new ChainNode<T>;
	 y->data = x;
	 if (k) //在p之后插入
	 {
		 y->link = p->link;
		 p->link = y;
	 }
	 else
	 {
		 y->link = first;
		 first = y;
	 }
	 if (!y->link)
	 {
		 last = y; //记录最后一个节点
	 }
	 return *this;
 }

删除Erase():

 //删除说有节点
 template<class T>
  void Chain<T>::Erase()
 {
	  ChainNode<T> *next;
	  while (first)
	  {
		  next = first->link;
		  delete first;
		  first = next;
	  }
 }

添加Append(const T & x):

  //在链表尾部添加一个节点
  template<class T>
  Chain<T>& Chain<T>::Append(const T & x)
  {
	  ChainNode<T> *y;
	  y = new ChainNode<T>;
	  y->data = x; y->link = 0;
	  if (first) //链表非空
	  {
		  last->link = y;
		  last = y;
	  }
	  else
	  {
		  first = last = y;
	  }
	  return *this;
  }

已上函数都是书上的源码部分,对应的函数都已经实现,下面部分为后面习题部分自己实现的函数功能,自己写的测试可以通过,若你发现有些有问题欢迎在下面评论。

复制构造函数:

 //复制构造函数
 template<class T>
Chain<T>::Chain(const Chain<T>& Val)
 {
	 this->Erase(); //先清除所有数据
	 ChainNode<T> * next = Val.first;
	 while (next)
	 {
		 this->Append(next->data);
		 next = next->link;
	 }
 }

//重载 = 
  template<class T>
  Chain<T>& Chain<T>::operator=(const Chain<T>& x)
  {
	  this->Erase(); //先清除所有数据
	  ChainNode<T> * next = x.first;
	  while (next)
	  {
		  this->Append(next->data);
		  next = next->link;
	  }
	  return *this;
  }

反转 Reverse():

//次序反转
  template<class T>
   Chain<T>& Chain<T>::Reverse()
  {
	   if (first ==0 && first == last && first->link == 0)
	   {
		   return *this;
	   }
	   ChainNode<T> * current = first; //记录位置
	   ChainNode<T> * pre = NULL;
	   last = first;  //头变尾
	   //好好体会一下这个
	  while (first)
	  {
		  current = first;
		  first = first->link;
		  current->link = pre;
		  pre = current;
	  }
	  first = current; //current 为头指针
	  return *this;
  }

交叉线性Alternate(const Chain<T>& list1, const Chain<T>& list2)

 //交叉线性
   template<class T>
    Chain<T>& Chain<T>::Alternate(const Chain<T>& list1, const Chain<T>& list2)
   {
		if (this == &list1 && this == &list2)
		{
			cout << "参数不能是本身变量" << endl;
			return *this;
		}
		//清除前链表的数据
		this->Erase();
//		int length = list1.Length() + list2.Length();
		ChainNode<T> * pList1 = list1.first;
		ChainNode<T> * pList2 = list2.first;
		while (pList1 && pList2)
		{
			this->Append(pList1->data);
			this->Append(pList2->data);
			//指向下个
			pList1 = pList1->link;
			pList2 = pList2->link;
		}

		if (!pList1)   //pList1为空的话 
		{
			while (pList2)
			{
				this->Append(pList2->data);
				pList2 =  pList2->link;
			}
		}
		else  
		{
			while (pList1)
			{
				this->Append(pList1->data);
				pList1 = pList1->link;
			}
		}
		return *this;
   }

合并有序数据Merge(const Chain<T>& list1, const Chain<T>& list2)

	//合并数据 前提数据必须是有序的。
   template<class T>
  Chain<T>& Chain<T>::Merge(const Chain<T>& list1, const Chain<T>& list2)
  {
	  //清除前链表的数据
	  if (this == &list1 && this == &list2)
	  {
		  cout << "参数不能是本身变量" << endl;
		  return *this;
	  }
	  //清除前链表的数据
	  this->Erase();
	  //获取两个链表的头节点
	  ChainNode<T> * pList1 = list1.first;
	  ChainNode<T> * pList2 = list2.first;
	  while (pList1 && pList2)
	  {
		  if (pList1->data <= pList2->data)
		  {
			  this->Append(pList1->data);
			  pList1 = pList1->link;
		  }
		  else
		  {
			  this->Append(pList2->data);
			  pList2 = pList2->link;
		  }
	  }
	  //当其中一个链表为空或者都为空,开始下面处理
	  if (!pList1)
	  {
		  while (pList2)
		  {
			  this->Append(pList2->data);
			  pList2 = pList2->link;
		  }
	  }
	  else
	  {
		  while (pList1)
		  {
			  this->Append(pList1->data);
			  pList1 = pList1->link;
		  }
	  }  	
	  return *this;
  }

 排序sort()

 //选择排序
  template<class T>
 void Chain<T>::sort()
  {
	 ChainNode<T> * p = first->link; //获取
	 ChainNode<T> * min = first; //先获取头节点数据为最小值

	 while(min)
	 {
		 p = min->link;
		 while (p)
		 {
			 if (min->data > p->data)
			 {
				 T temp = min->data;
				 min->data = p->data;
				 p->data = temp;
			 }
			 p = p->link;
		 }
		 min = min->link; //找到下一位
	 }

  }

这里是书上没有要求的,为了后面测试方便。

拆分Split(Chain<T>& list1, Chain<T>& list2):

 template<class T>
void Chain<T>::Split(Chain<T>& list1, Chain<T>& list2)
 {
	//拆分的两个变量不能为当前拆分的值
	if (this == &list1 && this == &list2)
	{
		cout << "参数不能是本身变量" << endl;
		return ;
	}
	//若要拆分 list1 与 list2 首先要滞空
	list1.Erase();
	list2.Erase();
	ChainNode<T> * current = first;
	int index = 1;
	while (current)
	{
		if ((index & 1) == 1) //当为奇数的时候
		{
			list1.Append(current->data);
	
		}
		else   //当为偶数的时候
		{
			list2.Append(current->data);

		}
		//到达下个数据
		current = current->link;
		index++;
	}

 }

测试函数:

 void testChain()
  {
	  Chain<int> c;
	  cout << "新建链表:     " << endl;
	  cout << "链表是否为空:   " << c.IsEmpty() << endl;
	  cout << "链表的长度:    " << c.Length() << endl;
	  cout << "链表为:     " << c << endl << endl;
	  //测试插入函数
	  c.Insert(0, 1).Insert(1, 2).Insert(2, 3).Insert(3,4);
	  cout << "链表是否为空:   " << c.IsEmpty() << endl;
	  cout << "链表的长度:    " << c.Length() << endl;
	  cout << "链表为:     " << c << endl << endl;

	  int value = 0;
	  //find函数查找
	  c.Find(2, value);
	  cout << "测试Find()函数---c.Find(2,x):" << endl;
	  cout << "x为:   " << value << endl << endl;

	  //查找函数
	  cout << "测试Search():" << endl;
	  cout << "元素0的位置为:  " << c.Search(0) << endl;
	  cout << "元素2的位置为:  " << c.Search(2) << endl << endl;

	  //测试删除
	  cout << "开始删除链表" << endl;
	  cout << "源链表:  " << c << endl;
	  c.Delete(2, value);
	  cout << "删除的数据是:  " << value <<endl;
	  cout << "删除后的链表:  " << c << endl;

	  //append 函数测试
	  c.Append(10);
	  cout << "插入后链表为:  " << c << endl << endl;

	  //测试新遍历器
	  int * va;
	  ChainIterator<int> d;
	  va = d.Initialize(c);
	  while (va)
	  {
		  cout << *va << " ";
		  va = d.Next();
	  }
	  cout << endl;

	  //测试构建复制函数
	  cout << "构建复制函数" << endl;
	  Chain<int> NewNum(c);
	  cout << "源链表:  " << c << endl;
	  cout << "新链表:  " << NewNum << endl;
	  //测试 =
	  cout << "=号赋值" << endl;
	  NewNum = c;
	  cout << "源链表:  " << c << endl;
	  cout << "新链表:  " << NewNum << endl;
	  cout << endl;

	  //测试反转函数
	  cout << "源链表:        " << c << endl;
	  c.Reverse();
	  cout << "反转后的链表:  " << c << endl;

	  cout << endl;

	  cout << " 测试Alternate 函数 " << endl;
	  Chain<int> testAl;
	  testAl.Alternate(NewNum,c);
	  cout << "NewNum 列表是:   " << NewNum << endl;
	  cout << "c 列表是:        " << c << endl;
	  cout << "testAl 列表是:   " << testAl << endl;
	  cout << endl;

	  //排序测试 选择排序
	  cout << "排序测试" << endl;
	  cout << "c 列表是:        " << c << endl;
	  cout << "testAl 列表是:   " << testAl << endl;
	  c.sort();
	  testAl.sort();
	  cout << "排序后 c 列表是:        " << c << endl;
	  cout << "排序后 testAl 列表是:   " << testAl << endl;

	  //排序后测试Merge 函数
	  cout << "排序后测试Merge 函数" << endl;
	  Chain<int> testMerge;
	  testMerge.Merge(c, testAl);
	  cout << "Merge(c, testAl) 函数: " << testMerge << endl;
	  cout << endl;
		  //测试Split 
	  cout << "测试Split 函数" << endl;
      Chain<int> one, two;
	  cout << "拆分前testMerge数据:" << testMerge << endl;
	  cout << "拆分前one数据:      " << one << endl;
	  cout << "拆分前two数据:      " << two << endl;
	  testMerge.Split(one, two);
	  cout << "拆分后testMerge数据:" << testMerge << endl;
	  cout << "拆分后one数据:      " << one << endl;
	  cout << "拆分后two数据:      " << two << endl;
  }

主函数:

#include <iostream>
#include "listearLine.h"
#include "Chain.h"
using namespace std;

int main()
{
	//测试线性表数组
	//testLinearList();
	//测试线性表链表
	testChain();
	return 0;
}

程序运行结果:

新建链表:
链表是否为空:   1
链表的长度:    0
链表为:

链表是否为空:   0
链表的长度:    4
链表为:     1 2 3 4

测试Find()函数---c.Find(2,x):
x为:   2

测试Search():
元素0的位置为:  0
元素2的位置为:  2

开始删除链表
源链表:  1 2 3 4
删除的数据是:  2
删除后的链表:  1 3 4
插入后链表为:  1 3 4 10

1 3 4 10
构建复制函数
源链表:  1 3 4 10
新链表:  1 3 4 10
=号赋值
源链表:  1 3 4 10
新链表:  1 3 4 10

源链表:        1 3 4 10
反转后的链表:  10 4 3 1

 测试Alternate 函数
NewNum 列表是:   1 3 4 10
c 列表是:        10 4 3 1
testAl 列表是:   1 10 3 4 4 3 10 1

排序测试
c 列表是:        10 4 3 1
testAl 列表是:   1 10 3 4 4 3 10 1
排序后 c 列表是:        1 3 4 10
排序后 testAl 列表是:   1 1 3 3 4 4 10 10
排序后测试Merge 函数
Merge(c, testAl) 函数: 1 1 1 3 3 3 4 4 4 10 10 10

测试Split 函数
拆分前testMerge数据:1 1 1 3 3 3 4 4 4 10 10 10
拆分前one数据:
拆分前two数据:
拆分后testMerge数据:1 1 1 3 3 3 4 4 4 10 10 10
拆分后one数据:      1 1 3 4 4 10
拆分后two数据:      1 3 3 4 10 10
请按任意键继续. . .

本文例子程序:

链接:https://pan.baidu.com/s/1m8KlkXVzzNGKmKE9I9lwCA   提取码:c2te

如果遇到什么问题可以联系我,关注我的博客,一起加油学习吧。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章