C++数据结构-单链表创建

版权声明:QQ:763905926 未经允许请勿转载,转载请注明出处! https://blog.csdn.net/lms1008611/article/details/81916359

    前边我们创建了顺序存储结构的线性表,简称顺序表,顺序表最大的问题是:插入和删除需要移动大量的元素。为了解决 这个问题, 我们引入链式存储结构的线性表,简称链表,链表与顺序表不同,链表的每个结点在内存中是分开存放的,每个结点都包含数据域和指针域:
    - 数据域存储数据元素本身
    - 指针域存储相邻结点的地址

链式存储结构的线性表有
    - 单链表每个结点只包含直接后继的地址信息
    - 循环链表单链表中的最后一个结点的直接后继为第一个结点
    - 双向链表单链表中的结点包含直接前驱和后继的地址信息
    - 双向循环链表双向链表的最后一个结点的后继为第一个结点,第一个结点的前驱为最后一个结点

    链表中的基本概念
    - 头结点 : 链表中的辅助结点,包含指向第一个数据元素的指针
    - 数据结点:链表中代表数据元素的结点,包含数据元素与地址两部分
    - 尾结点:链表中的最后一个数据结点,包含的地址信息为空

    这里我们创建的单链表,结点可以 定义为如下

struct Node : public MyObject
{
    T value;    //数据域
    Node* Next;    //指针域
};

    单链表的内部结构如下,头结点不存储实际的数据元素,只是为了数据元素定位,方便插入和删除操作

下边我们直接来看代码中的实现

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

#include "List.h"

namespace MyLib
{
template <typename T>
class LinkList : public List<T>
{
private:
    struct Node : public MyObject
    {
    	T value;	//数据域
    	Node* Next;	//指针域
    };

    mutable struct : public MyObject
    {
	char reserved[sizeof(T)]; //作为占位用,不存放数据
	Node* Next;
    }m_header;	
    int m_length;	//存储链表长度

    Node* m_current;	//指向当前的结点
    int m_step;			//
	
    Node* position(int index) const		//获取index处的结点
    {
	Node* ret = reinterpret_cast<Node*>(&m_header);
	for (int i=0; i<index; i++)
        {
	    ret = ret->Next;
	}
	return ret;
    }
    virtual Node* create()
    {
	return new Node;
    }

    virtual void destroy(Node* p)
    {
	delete p;
    }

public:
    LinkList()
    {
	m_length = 0;
	m_header.Next = NULL;
	m_current = NULL;
	m_step = 1;
    }

    bool insert( const T& e)	//尾部插入结点
    {
	return insert(m_length, e);
    }

    bool insert(int index, const T& e)	 //插入结点
    {
	bool ret = ( (0 <= index)&&(index <= m_length) );
	if (ret)
	{
	    Node* currentNode = position(index);
	    Node* newNode = create();
	    newNode->value = e;
	    newNode->Next = currentNode->Next;
	    currentNode->Next = newNode;
	    m_length++; 
	}
	else
	{
	    THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception...");
	}

	return ret;
    }

    bool remove(int index)	//删除结点
    {
	bool ret = ( (0 <= index)&&(index < m_length) );
	if (ret)
	{
	    Node* currentNode = position(index);
	    Node* toRemove = currentNode->Next;
            if (m_current == toDel)
	    {
	        m_current = toDel->Next;
	    }
	    currentNode->Next = toRemove->Next;
            m_length--;
	    destroy(toRemove);
	}
	else
	{
	    THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception...");
	}
	return ret;
    }

    bool get(int index, T& e)	//获取具体位置的结点元素
    {
	bool ret = ( (0 <= index)&&(index < m_length) );
	if (ret)
	{
	    Node* currentNode = position(index);
            e = currentNode->Next->value;
	}
	else
	{
	    THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception...");
        }
	return ret;
    }
    bool set(int index, const T& e)const	//设置具体位置的结点元素
    {
	bool ret = ( (0 <= index)&&(index < m_length) );
	if (ret)
	{
	    Node* currentNode = position(index);
	    currentNode->Next->value = e;
	}
	else
	{
	    THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception...");
	}
	return ret;
    }

    int find(const T& e) const		//链表中寻找元素位置
    {
	Node* tofind = m_header.Next;
	for (int i=0; i<m_length; i++)
	{
	    if (e == tofind->value)
	    {
		return i;
	    }
	    else
	    {
		tofind = tofind->Next;
	    }
	}
	return -1;
    }

    void move(int index, int step = 1)	//游标移动初始化
    {
	bool ret = ( (0<=index)&&(index < m_length) );
	if (ret)
	{
	    m_current = position(index)->Next;
	    m_step = step;
	}
	else
	{
	    THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Exception...");
	}
    }

    void next()	//游标移动到下一个位置
    {
	int i=0;
	while ( (!end())&&(i<m_step) )
	{
	    m_current = m_current->Next;
	    i++;
	}
    }

    bool end()	//判断游标是否到达链表最尾处
    {
        return m_current == NULL;
    }

    T current()	//返回游标所指处的元素
    {
        if (!end())
	{
	    return m_current->value;
	}
	else
	{
	    THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Exception...");
	}
    }

    int length()const	//返回列表长度
    {
	return m_length;
    }
    void clear()	//清空列表
    {
        while(m_header.Next)
	{
            remove(m_length-1);
	}
    }
};
}

#endif	//__LINKLIST_H__

上边我们就基本把单链表的内容实现完了,下边我们来在main函数中使用一下

#include <iostream>
#include <string>
#include "LinkList.h"

using namespace std;
using namespace MyLib;

int main()
{
    LinkList<int> list;

    for (int i=0; i<10; i++)
    {
	list.insert(i);
    }

    list.set(2, 23);

    for (list.move(0); !list.end(); list.next())	//采用游标方式遍历链表
    {
	cout << list.current() << endl;
    }

    cout << "find(3) = " << list.find(3) << endl;

    system("pause");

    return 0;
}

编译执行

总结
    - 链表中的数据元素在物理内存中无相邻关系
    - 链表中的结点都包含数据域指针域
    - 头结点用于辅助数据元素的定位,方便插入和删除操作
    - 插入和删除操作需要保证链表的完整性

猜你喜欢

转载自blog.csdn.net/lms1008611/article/details/81916359