数据结构学习记录连载3(链表的学习)

基本要求:

1) 用模板方法建立链表的结点类ListNode和单链表类LinList,编写程序实现向单链表插入100整数,然后,以插入次序删除这100个整数。

提高要求:

1) 简单修改程序,将单链表类LinList改为双向循环链表类。向双向循环链表插入100字符,然后,以插入次序删除这100个字符。

2) 编写函数实现单链表类LinList的对象B连接到单链表类LinList的对象A的尾部:Void Concatenate(LinList& A, LinList& B)。

1.ListNode.h结点定义:

/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:ListNode.h
* 摘 要: 节点类的定义
*
* 当前版本:1.0
* 作 者: 吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/

#include<iostream.h>
#include<stdio.h>

template<class T> class LinkList; //前视定义,否则,无法定义友元
template<class T> class ListNode
{
 friend class LinkList<T>;  //定义友元
private:
 ListNode<T> *next;    //指向下一个结点的指针
public:
 T data;
 ListNode(ListNode<T> *ptrNext = NULL); //构造函数,用于构造头结点
 ListNode(const T& item, ListNode<T> *ptrNext = NULL);//构造函数,非头结点
 ~ListNode() {};     //析构函数
 friend void Concatenate(LinkList<T>& target, LinkList<T>& souce);
};

template<class T>
ListNode<T>::ListNode(ListNode<T> *ptrNext):next(ptrNext)
{
 
}

template<class T>
ListNode<T>::ListNode(const T &item, ListNode<T> *ptrNext)
{
 data = item;
 next = ptrNext;
}

2.LinkList.h定义单链表类及实现:

/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:LinkList.h
* 摘 要: 单链表类的定义
*
* 当前版本:1.0
* 作 者: 吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/

#include "ListNode.h"

template <class T>
class LinkList
{
private:
 ListNode<T> *head;      //指向头结点的指针
 int size;        //单链表的元素个数
 ListNode<T> *currPtr;     //当前结点
public:
 LinkList(void);       //构造函数
 ~LinkList();      //析构函数

 //线性表操作要求的成员函数
 int GetListSize(void) const;   //返回链表的元素个数
 int ListIsEmpty(void) const;   //判断单链表是否为空
 ListNode<T> *Index(int pos);   //定位
 void Insert(const T& item, int pos); //插入
 T Delete(int pos);      //删除
 T GetData(int pos);      //取元素
 void ClearList(void);     //清空链表

 //遍历单链表的成员函数
 ListNode<T> *Reset(int pos=0);   //把第pos个结点设置为当前结点currPtr
 ListNode<T> *Next(void);    //currPtr指向下一个结点
 int EndOfList(void) const;    //currPtr是否指在链表尾

 friend void Concatenate(LinkList<T>& target, LinkList<T>& souce);
}; 

 

/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:LinkList.cpp
* 摘 要: 单链表的各个功能函数的现实
*
* 当前版本:1.0
* 作 者: 吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/

template <class T>
LinkList<T>::LinkList(void) 
{
 size = 0;
 head = new ListNode<T>();
}

template <class T>
LinkList<T>::~LinkList()
{
 ClearList(); //释放所有非头结点的结点
 delete head; //释放头结点
}

/*
* 函数名称: GetListSize
* 输 入:
* 输 出:
* 功能描述: 返回顺序表的元素个数size
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
int LinkList<T>::GetListSize(void) const 
{
 return size;
}

/*
* 函数名称: ListIsEmpty
* 输 入:
* 输 出:
* 功能描述: 判断是否为空,空返回1;非返回0
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
int LinkList<T>::ListIsEmpty(void) const
{
 return size == 0 ? 1 : 0;
}

/*
* 函数名称: Index
* 输 入: pos
* pos: 定位数据元素结点
* 输 出:
* 功能描述: 定位至第pos个数据元素结点,返回指向第pos个结点的指针
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
ListNode<T> *LinkList<T>::Index(int pos)
{
 if (pos < -1 || pos > size)
 {
  cout << "参数pos越界出错!" << endl;
  exit(0);
 }

 if (pos == -1)
 {
  return head;
 }

 ListNode<T> *p = head->next;
 int i = 0;
 while (p != NULL && i <pos)
 {
  p = p->next;
  i++;
 }

 return p;
}

/*
* 函数名称: Insert
* 输 入: pos
* pos: 插入数据元素结点的位置
* item: 插入数据结点的数据
* 输 出:
* 功能描述: 在pos个结点之前插入一个data域为item的新结点
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
void LinkList<T>::Insert(const T& item, int pos)
{
 if (pos < 0 || pos > size)
 {
  cout << "参数pos越界出错!" << endl;
  exit(0);
 }

 ListNode<T> *p = Index(pos - 1);
 ListNode<T> *newNode = new ListNode<T>(item, p->next);
 p->next = newNode;
 size++;
}

/*
* 函数名称: Delete
* 输 入: pos
* pos: 删除数据元素结点的位置
* 输 出:
* 功能描述: 删除第pos个结点,并返回被删除结点的data
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
T LinkList<T>::Delete(int pos)
{
 T temp;
 if (pos < 0 || pos > size-1)
 {
  cout << "参数pos越界出错!" << endl;
  exit(0);
 }

 ListNode<T> *q, *p = Index(pos - 1);
 q = p->next;
 p->next = p->next->next;
 temp = q->data;
 delete q;
 size--;

 return temp;
}

/*
* 函数名称: ClearList
* 输 入: pos
* pos: 删除数据元素结点的位置
* 输 出:
* 功能描述: 清空表为初始化状态
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
void LinkList<T>::ClearList(void)
{
 ListNode<T> *p = head->next;
 ListNode<T> *q;

 while (p != NULL)
 {
  q = p;
  p = p->next;
  delete q;
 }
 size = 0;
}

/*
* 函数名称: Reset
* 输 入: pos
* pos: 数据元素结点的位置
* 输 出:
* 功能描述: 使currPtr指向结点pos,并返回currPtr
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
ListNode<T> *LinkList<T>::Reset(int pos)
{
 if (pos < -1 || pos > size - 1)
 {
  cout << "参数pos越界出错!" << endl;
  exit(0);
 }

 if (pos == -1)
 {
  return head;
 }

 if (pos == 0)
 {
  currPtr = head->next;
 }
 else
 {
  currPtr = head->next;
  ListNode<T> prevPtr = head;
  for (int i=0; i<pos; i++)
  {
   prevPtr = currPtr;
   currPtr = currPtr->next;
  }
 }

 return currPtr;
}

/*
* 函数名称: Next
* 输 入: 
* 输 出:
* 功能描述: 使currPtr指向下一个结点
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
ListNode<T> *LinkList<T>::Next(void)
{
 if (currPtr != NULL)
 {
  currPtr = currPtr->next;
 }

 return currPtr;
}

/*
* 函数名称: EndOfList
* 输 入: 
* 输 出:
* 功能描述: currPtr是否指在链表尾
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
int LinkList<T>::EndOfList(void) const
{
 return currPtr == NULL ? 1 : 0;
}

/*
* 函数名称: GetData
* 输 入: pos
* pos: 需要得到结点数据的位置
* 输 出:
* 功能描述: 获取pos处结点的数据
* 作 者: 吴友强
* 日 期: 2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
T LinkList<T>::GetData(int pos)
{
 if (pos < 0 || pos > size-1)
 {
  cout << "参数pos越界出错!" << endl;
  exit(0);
 }

 ListNode<T> *p = Index(pos);
 return p->data;
}

 

4.LinkListTest.cpp测试程序:

/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:SeqListTest.cpp
* 摘 要: 测试链表的功能
*
* 当前版本:1.0
* 作 者: 吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/

#include <iostream.h>
#include <stdlib.h>

#include "LinkList.h"

int main(int argc, char *argv[])
{
 LinkList<int> targetList, sourceList;

 for (int i=0; i<10; i++)
 {
  targetList.Insert(i+10, i);
 }

 for (i=0; i<5; i++)
 {
  sourceList.Insert(i+5, i);
 }
//  cout << "测试GetData()成员函数结果如下:" << endl;
//  int n = linkList.GetListSize();
//  for (i=0; i<n; i++)
//  {
//   cout << linkList.GetData(i) << " ";
//  }
//
//  cout << endl << "测试遍历成员函数结果如下:" << endl;
//  ListNode<int> *p = linkList.Reset(0);
//
//  while (!linkList.EndOfList())
//  {
//   cout << p->data << " ";
//   p = linkList.Next();
//  }
//
//  cout << endl << "测试Delete()成员函数结果如下:" << endl;
//  n = linkList.GetListSize();
//  for (i=n-1; i>=0; i--)
//  {
//   linkList.Delete(i);
//  }
//
//  cout << "测试GetData()成员函数结果如下:" << endl;
//  n = linkList.GetListSize();
//  for (i=0; i<n; i++)
//  {
//   cout << linkList.GetData(i) << " ";
//  }

 Concatenate(targetList, sourceList);

 int n = targetList.GetListSize();
 for (i=0; i<n; i++)
 {
  cout << targetList.GetData(i) << " ";
 }
 return 0;
}

5.注意事项:(1)如果单链表的定义与接口的实现分开到两个不同的头文件和CPP文件,编译会出错,解决把法是把CPP文件删除在头文件最后加上一句:#include "LinkList.cpp"

(2)上面注释部分是测试基本函数功能的,我同时在里面测试了提高要求2,提高2的现实在下一篇中给出。

 

posted @ 2009-10-18 10:45  蔷薇理想人生  阅读(276)  评论(0编辑  收藏  举报