数据结构与算法_线性表_单链表_常用操作接口和复杂度分析

线性表_单链表_常用操作接口和复杂度分析

  • 链表的优点:
    内存利用率高,不需要大块连续内存;
    插入和删除不需要移动节点,时间复杂度为O(1);
    不需要专门进行扩展操作,需要节点时候直接申请即可。
  • 链表的缺点
    内存占用量大,每一个节点多出存放地址的空间:每个节点多了一个指针,假如有100万整型数据,假设指针占4字节,那么100w整型需要400w字节;如果用链表实现,每个节点多出一个指针,存放100w整型数组需要800万字节;
    链表每个节点都不连续,无法内存随机访问;
    链表搜索效率不高,只能从头节点开始搜索。
  • 数组和链表的应用对比
    在通用情况下:如果下标访问/随机访问,那么用数组合适;但是数组的搜索还是O(n);
    如果增加和删除频繁,用链表更合适O(1);链表的搜索也是O(n);

下面的代码用C++语法实现了链表接口的定义:
尾插,头插,打印链表,删除单个节点和所有重复节点,最后释放链表内存;


#include 
#include 
#include 
using namespace std;

// 节点类型
struct Node
{
	Node(int data = 0) :data_(data), next_(nullptr) {}
	int data_;
	Node *next_;
};

class Clink
{
public:
	Clink()
	{
		// 给head_初始化指向头结点
		head_ = new Node();
	}
	~Clink()
	{
		// 节点释放
		Node *p = head_;
		while (p != nullptr)
		{
			head_ = head_->next_;
			delete p;
			p = head_;
		}
		head_ = nullptr;
	}
public:
	// 尾插 O(n)
	void InsertTail(int val)
	{
		Node *p = head_;
		// 找到当前链表末尾节点
		while (p->next_ != nullptr)
		{
			p = p->next_;
		}
		// 生成新节点
		Node *node = new Node(val);
		
		// 插入到尾部
		p->next_ = node;
	}

	// 链表的头插 O(1) 
	void InsertHead(int val)
	{
		// 生成新节点
		Node *node = new Node(val); // new = 开辟新节点 + 调用构造初始化新节点
		// 新节点先指向头结点的下一个节点
		node->next_ = head_->next_;
		// 头节点指向新节点
		head_->next_ = node;
	}

	// 打印链表
	void Show()
	{
		Node *p = head_->next_; // 头结点没有存放数据,所以从第一个节点开始打印
		while (p != nullptr)   // 只有寻找尾结点时候,才p->next_ = nullptr 这样的用法
		{						// 这样就会 漏掉 尾结点
			cout << p->data_ << " ";
			p = p->next_;
		}
		cout << endl;
	}
	// 删除所有值为val的节点
	int Remove(int val)
	{
		// 先搜索头节点
		Node *p = head_->next_;
		Node *q = head_;   // 记住跟屁虫
		while (p != nullptr)
		{
			if (p->data_ == val)
			{
				q->next_ = p->next_;
				delete p;
				return 0;
				//p = q->next_; //  删除后再让p继续指向q下一个,就可以删除重复节点
			}
			else
			{
				q = p;
				p = p->next_;
			}
		}
		cout << "未找到" << endl;
		return -1;

	}

	void RemoveAll(int val)
	{
		Node *q = head_;
		Node *p = head_->next_;

		while (p != nullptr)
		{
			if (p->data_ == val)
			{
				q->next_ = p->next_;
				delete p;
				p = q->next_;
			}
			else
			{
				q = p;
				p = p->next_;
			}
		}
		return;
	}
	// 链表搜索  O(n)  注意和数组的下标访问区别。
	bool Find(int val)
	{
		Node *p = head_->next_;
		while (p != nullptr)
		{
			if (p->data_ == val)
			{
				return true;
			}
			else
			{
				p = p->next_;
			}
		}
		return false;
	}
private:
	Node *head_;
	// 可以增加一个新节点指向尾结点,降低尾插的时间复杂度
};

int main()
{
	Clink link;
	srand(time(0));
	for (int i = 0; i < 10; i++)
	{
		int val = rand() % 100;
		link.InsertHead(val);
		cout << val << " ";
	}
	cout << endl;
	link.Show();
	link.InsertTail(250);
	link.InsertTail(250);
	link.Show();

	link.RemoveAll(250);
	link.Show();
	system("pause");
	return 0;
}

数据结构与算法_线性表_单链表_常用操作接口和复杂度分析_第1张图片

你可能感兴趣的:(数据结构与算法,链表,数据结构,单链表,链表的接口实现,单链表增删查改)