跟我学数据结构:(3)单向链表

本文介绍用C++实现单向链表的方法,包括创建、插入、删除等操作,并通过示例代码展示如何使用单向链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跟我学数据结构:(3)单向链表

摘要:

本文通过示例,演示了用C++实现数据结构的单向链表。

读者对象:

对C++有一定基础的同学。

技术要点:

C++数据抽象

构造函数

析构函数

运算符重载

编码规范初步

指针

友元

声明

本文中相关数据结构及代码是为教学需要而设计,不适用于商业产品。

链表的引入

我们在上节课“数组”是,讲到了对数据的遍历、查找、插入和删除。当我们在对数组进行插入或删除操作的时候,会引起操作点之后的元素整体移动,大量的数据移动(内存复制)会产生能下降的问题。链表正是避免了这一问题。

注:本系列教程以代码,示例演示为主,关于链表的数学定义请参考其它书籍。

链表的设计

链表一般提供了以下操作:

1) 创建链表 creaList()

2) 在指定节点后面插入一个新的节点 insertAfter()

3) 删除指定的值的节点 remove()

4) 遍历所有节点 operator<<()

5) 销毁所有链表

插入节点的操作示意图

操作前

clip_image002

操作过程

(1)

clip_image004

(2)

clip_image006

(3)

clip_image008

删除节点的操作示意图

操作前

clip_image010

操作步骤

(1)

clip_image012

(2)

clip_image014

代码及运行结果
//file: main.cpp
//desc: this program illustrate how to use linked-list
//date: 2009-6-1
//author: Stone Jiang 
  

#include 
 

  using 
  namespace std;


  typedef  
  int  Data_T;

  class Node_T
{

  public:
	
  // [1]
	
  explicit Node_T(Data_T x);
	Node_T();
	~Node_T();

  public:
	
  // public interface
	
  void next(Node_T* next);
	Node_T* next(
  void);
	Data_T value();
    
  // [2]
	
  friend ostream& 
  operator << (ostream& os, Node_T* header);

  private:
    Data_T value_;
	Node_T* next_;
};


Node_T::Node_T()
:value_(0),next_(0)
{
	
  //cout << " create " << this->value_ << endl;

}

Node_T::Node_T(Data_T x)
:value_(x),next_(0)
{
	
  //cout << " create " << this->value_ << endl;

}

Data_T Node_T::value()
{
	
  return 
  this->value_;
}

Node_T::~Node_T()
{
	
  //cout << " destroy " << this->value_ << endl;
}


  void Node_T::next(Node_T* next)
{
	
  this->next_ = next;
}

Node_T* Node_T::next()
{
	
  return 
  this->next_;
}



  //= create List
Node_T*  createList();


  //= Insert a new node @
   
     after @
    
      in the list 0
    
   

  //  success return 0,otherwise  return non-zero

  int insertAfter(Node_T* header,Data_T x,Node_T* node);


  //= Remove @
   
     from list
   

  int remove(Node_T* header,Data_T x);


  //= destroyList

  int destroyList(Node_T* header);

ostream& 
  operator << (ostream& os, Node_T* header);


  int main(
  int, 
  char**)
{

	Node_T* header = createList();
	cout << header;
	Node_T* one  = 
  new Node_T(1);
	insertAfter(header,0,one);
    cout << header;

	Node_T* three = 
  new Node_T(3);
	insertAfter(header,1,three);
	cout << header;

	Node_T* two = 
  new Node_T(2);
	insertAfter(header,1,two);
	cout << header;

	Node_T* five = 
  new Node_T(5);
	insertAfter(header,3,five);
	cout << header;

	cout << "
  remove :"<
  
   return 0;
}


Node_T* createList()
{
	Node_T* header = 
   new Node_T(0);
	
   return header;
}


   int insertAfter(Node_T* header,Data_T x,Node_T* node)
{
	
   int result = -1;
	
   if (header)
	{
		Node_T* current = header;
		
   if (current->value() == x || current->next() == 0)
		{
			
   // [1]
			node->next(current->next());
			current->next(node);
			result = 0;
		}
		
   else
		{
			
   return insertAfter(current->next(),x,node);
		}
	}

	
   return result;
}


   int remove(Node_T* header,Data_T x)
{
	
   int result = -1;

	
   if (header)
	{
		Node_T* prev = header;
		Node_T* current = header->next();
		
   if (current->value() == x)
		{
			prev->next(current->next());
			
   delete current;
			current  = 0;
			result = 0;
		}
		
   else
		{
			
   return remove(current,x);
		}
	}
	
   return result;
}


   int destroyList(Node_T* header)
{

	Node_T* current = header;
	
   while (current)
	{
		Node_T* temp = current;
		current = current->next();
		
   delete temp;
		temp = 0;
	}

	
   return 0;
}

ostream& 
   operator << (ostream& os,  Node_T* header)
{
	
   if (header)
	{
		Node_T* current = header;
		os << "
   ( " << current->value() << "
    ) ---> ";
		
		
   return  os << current->next();
	}
	
   else
	{
		cout << "
    ( END )" << endl;
	}

	
   return os;

}
  
 

 

( 0 ) --->  ( END )
( 0 ) ---> ( 1 ) --->  ( END )
( 0 ) ---> ( 1 ) ---> ( 3 ) --->  ( END )
( 0 ) ---> ( 1 ) ---> ( 2 ) ---> ( 3 ) --->  ( END )
( 0 ) ---> ( 1 ) ---> ( 2 ) ---> ( 3 ) ---> ( 5 ) --->  ( END )
remove :
( 0 ) ---> ( 1 ) ---> ( 2 ) ---> ( 5 ) --->  ( END )
( 0 ) ---> ( 2 ) ---> ( 5 ) --->  ( END )
代码说明

(1) 部分收入C++面向对象的特性。示例中演示了构造函数,重载了构造函数。

(2) 代码中使用了递归算法。由于链表的定义可以通过递归来定义,并且在之后的课程中我们将广泛的使用递归算法,所以,我们在本代码中使用了递归算法。

您能找出我们在哪些地方用到了递归吗?

(3) 重载 << 函数。 为了方便对链表的遍历和输入,我们重载了< <函数。同学们是否可以从main()中看到,使用了> <<()之后,代码变简洁了?

(4)

埋个伏笔

我们并没有对链表作完合的面向对象封装,所以在使用代码的时候,额外的增加了对链表是否有效作了判断。另外,为了使代码简洁,我们并对函数调用的返回值作检查。在创建和删除节点的时候,我们都使用了动态内存分配。如果我们插入从栈上的临时节点到链表中,将收内存问题。这些,我们都将在后续的课程中为大家解决。

### 如何利用 ChatGPT 学习数据结构 #### 利用在线教程和 AI 工具相结合的方式学习数据结构 对于希望通过 ChatGPT 来学习数据结构的学习者而言,可以采用一种混合模式来进行高效学习。一方面,可以通过阅读传统的教材或参加线上的视频课程来获取系统的理论知识;另一方面,则可借助像 ChatGPT 这样的先进人工智能平台获得个性化的指导和支持[^1]。 #### 创建有效的对话提示(Prompt) 为了更好地向 ChatGPT 提问并得到有用的回答,在准备问题时应当尽可能具体化自己的需求。比如当询问有关链表的操作时,可以说:“我想了解单向链表的工作原理及其常见操作(如插入节点、删除节点),能否给我讲解一下?”这样的提问方式有助于让机器更精准地回应用户的求知欲[^3]。 #### 实践练习的重要性 除了理论之外,动手实践同样不可或缺。建议定期设置一些编程挑战给自己,尝试解决不同难度级别的题目。这不仅能够加深对知识点的理解程度,还能提高解决问题的能力。例如,“请帮我设计一道基于二叉树遍历的应用题”,通过这种方式不断积累经验。 #### 结合其他资源辅助学习 虽然 ChatGPT 是一个强大的工具,但在某些情况下可能还需要查阅更多外部资料作为补充说明。因此推荐同时关注官方文档、开源项目以及社区论坛等渠道的信息更新情况,以便及时跟进最新的发展动态和技术趋势[^4]。 ```python # 示例:定义一个简单的栈类用于理解堆栈这种数据结构 class Stack: def __init__(self): self.items = [] def is_empty(self): return not bool(self.items) def push(self, item): self.items.append(item) def pop(self): return self.items.pop() def peek(self): if not self.is_empty(): return self.items[-1] def size(self): return len(self.items) stack_example = Stack() print(f"Is the stack empty? {stack_example.is_empty()}") for i in range(5): # Push items onto the stack stack_example.push(i) print(f"The top element of the stack is: {stack_example.peek()}") while not stack_example.is_empty(): # Pop all elements from the stack print(stack_example.pop(), end=&#39; &#39;) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值