C++单向(循环)链表操作模板

作者: qiqi 分类: 数据结构 发布时间: 2026-05-22 12:54

单向链表模板:带头结点。

// 定义单链表结
struct Node
{
	int data;
	Node *next;
	Node(int v = 0): data(v), next(nullptr) {}
};
//函数声明部分
Node *createTail();         // 创建链表(尾插入法)
Node *createHead();         // 创建链表(头插入法)


int getLen(Node *head);                 // 获取链表长度
Node *getNodeAt(Node *head, int i);     // 按序号查找结点
Node *getNodeKey(Node *head, int key);  // 按值查找结点

bool insertAt(Node *head, int i, int e);// 指定位置插入结点
bool insertBeforeKey(Node *head, int key, int e);	//在指定值结点 “之前” 插入新的结点

bool removeAt(Node *head, int i);       // 按序号删除结点
bool removeKey(Node *head, int key);    // 按值删除结点
int removeAllKey(Node *head, int key);  // 删除所有值为key的结点


void reverseList(Node *head);           // 单链表反转
Node *mergeList(Node *h1, Node *h2);    // 合并两个有序链表(升序)

void bubbleSortList(Node *head);  // 单链表排序(冒泡排序)
void mergeSortList(Node *head); // 单链表排序(归并排序)

void printList(Node *head); // 打印链表
void freeList(Node *head);  // 释放链表所占内存

1.创建链表、打印输出链表以及释放链表模板:

#include <bits/stdc++.h>
using namespace std;

struct Node
{
	int data;
	Node *next;
	Node(int v = 0): data(v), next(nullptr) {}
};

Node *createTail();		// 创建链表(尾插入法)
Node *createHead();		// 创建链表(头插入法)

void printList(Node *head); // 打印链表
void freeList(Node *head);  // 释放链表所占内存

int main()
{
	// 1.创建链表
	//Node *head = createHead();
	Node *head = createTail();

	printList(head);
	freeList(head);
	return 0;
}

Node *createTail()
{
	// 新结点插入到当前链表的表尾,使其成为当前链表的尾结点。带头结点
	// 如果需要:可以把链表的大小或其它信息存储到头结点的data中。
	Node *head = new Node();
	Node *tail = head;
	int data;

	//while (scanf("%d", &data) == 1 && data != -1) //(-1结束)
	while (scanf("%d", &data), data != -1)
	{
		tail->next = new Node(data);
		tail = tail->next;
	}

	return head;
}

Node *createHead()
{
	// 每次插入的结点都作为链表的第一个结点,带头结点。
	// 如果需要:可以把链表的大小或其它信息存储到头结点的data中。
	Node *head = new Node();
	int data;

	//while (scanf("%d", &data) == 1 && data != -1) //(-1结束)
	while (scanf("%d", &data), data != -1)
	{
		Node *p = new Node(data);
		p->next = head->next;
		head->next = p;
	}

	return head;
}

// 打印链表所有数据用空格分隔
void printList(Node *head)
{
	// 方法一:
	Node *cur = head->next;
	if (!cur)
		return;

	printf("%d", cur->data);
	cur = cur->next;

	while (cur)
	{
		printf(" %d", cur->data);
		cur = cur->next;
	}
	printf("\n");

	/*
	// 方法二:
	for (Node *cur = head->next; cur; cur = cur->next)
	{
		if (cur != head->next)
			printf(" ");
		printf("%d", cur->data);
	}
	printf("\n");
	*/
}

// 释放链表所占内存
void freeList(Node *head)
{
	Node *tmp;
	while (head)
	{
		tmp = head;
		head = head->next;
		delete tmp;
	}
}

2.获取链表长度:int getLen(Node *head);。

// 获取链表长度
int getLen(Node *head)
{
	int len = 0;
	Node *p = head->next;
	while (p)
	{
		len++;
		p = p->next;
	}
	return len;
}

3. 按序号查找结点:Node *getNodeAt(Node *head, int i);

Node *getNodeAt(Node *head, int i)
{
	// 返回第i个结点指针,i从1开始,没找到返回nullptr。
	if (i < 1)
		return nullptr;

	Node *p = head->next;
	int pos = 1;
	while (p && pos < i)
	{
		p = p->next;
		pos++;
	}

	return p;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int i;
	scanf("%d", &i);

	// 2.返回第i个结点指针
	Node *p = getNodeAt(head, i);

	if (p)
		printf("%d\n", p->data);
	else
		printf("第%d个结点不存在!\n", i);

	// 3.释放链表
	freeList(head);
	return 0;
}

4.按值查找结点:Node *getNodeKey(Node *head, int key);

Node *getNodeKey(Node *head, int key)
{
	// 返回第一个值为key的结点指针, 不存在返回nullptr。
	Node *p = head->next;
	while (p && p->data != key)
	{
		p = p->next;
	}

	return p;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int key;
	scanf("%d", &key);

	// 2.返回第一个值为key的结点指针
	Node *p = getNodeKey(head, key);

	if (p)
		printf("%d\n", p->data);
	else
		printf("链表中不存在值为%d的结点!\n", key);

	// 3.释放链表
	freeList(head);
	return 0;
}

5.指定位置插入结点:bool insertAt(Node *head, int i, int e);

bool insertAt(Node *head, int i, int e)
{
	// 在第i个位置前插入值为e的新结点(插入到ai-1与ai之间),使e成为第i个结点。
	// i从1开始,i<=1头插,i>长度尾插,返回新头。

	if (i < 1)
		return false;  // 位置非法

	Node *p = head;
	int pos = 1;

	// 找到第 i-1 个结点
	while (p->next && pos < i)
	{
		p = p->next;
		pos++;
	}

	Node *newNode = new Node(e);
	newNode->next = p->next;
	p->next = newNode;

	return true;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int i, x;
	scanf("%d%d", &i, &x);

	// 2.在n之前插入x
	bool flag = insertAt(head, i, x);

	if (flag)
		printf("插入成功!\n");
	else
		printf("插入失败!\n");

	printList(head);

	// 3.释放链表
	freeList(head);
	return 0;
}

6.在指定值结点 “之前” 插入新的结点:bool insertBeforeKey(Node *head, int key, int e);

bool insertBeforeKey(Node *head, int key, int e)
{
	Node *p = head;
	//while (p->next->data != key && p->next != nullptr)//对空指针取成员 → 程序崩溃!
	while (p->next != nullptr && p->next->data != key)// p->next != nullptr 永远放左边
	{
		p = p->next;
	}

	if (p->next == nullptr)
		return false;

	Node *newNode = new Node(e);
	newNode->next = p->next;
	p->next = newNode;

	return true;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int n, x;
	scanf("%d%d", &n, &x);

	// 2.在n之前插入x
	bool flag = insertBeforeKey(head, n, x);
	if (flag)
		printList(head);
	else
		printf("%d不存在!\n", n);

	// 3.释放链表
	freeList(head);
	return 0;
}

7.按序号删除结点:bool removeAt(Node *head, int i);

bool removeAt(Node *head, int i)
{
	if (i < 1)
		return false;

	//删除第i个结点
	Node *p = head;
	int pos = 1;

	//找到第i-1个结点
	while (p->next && pos < i)
	{
		p = p->next;
		pos++;
	}

	if (!p->next) // i 值非法
		return false;

	Node *q = p->next;
	p->next = q->next;
	delete q;

	return true;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int i;
	scanf("%d", &i);

	// 2.删除第i个结点
	bool flag = removeAt(head, i);
	if (flag)
		printf("删除成功\n");
	else
		printf("删除失败\n");

	printList(head);
	// 3.释放链表
	freeList(head);
	return 0;
}

8.按值删除结点:bool removeKey(Node *head, int key);

bool removeKey(Node *head, int key)
{
	// 删除第一个值为key的结点
	Node *p = head;
	while (p->next && p->next->data != key)
	{
		p = p->next;
	}

	if (!p->next)
		return false;

	Node *q = p->next;
	p->next = q->next;
	delete q;

	return true;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int key;
	scanf("%d", &key);

	// 2.删除第一个值为key的结点结点
	bool flag = removeKey(head, key);
	if (flag)
		printf("删除成功\n");
	else
		printf("删除失败\n");

	printList(head);
	// 3.释放链表
	freeList(head);
	return 0;
}

9.删除所有值为key的结点:int removeAllKey(Node *head, int key);

int removeAllKey(Node *head, int key)
{
	int cnt = 0;
	Node *p = head;
	while (p->next)
	{
		if (p->next->data == key)
		{
			Node *q = p->next;
			p->next = q->next;
			delete q;
			cnt++;
		}
		else
			p = p->next;
	}
	return cnt;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	int key;
	scanf("%d", &key);

	// 2.删除所有值为key的结点
	int cnt = removeAllKey(head, key);
	printf("共删除%d个结点\n", cnt);

	printList(head);
	// 3.释放链表
	freeList(head);
	return 0;
}

10.单链表反转:void reverseList(Node *head);

void reverseList(Node *head)
{
	Node *pre = nullptr;
	Node *cur = head->next;

	while (cur)
	{
		Node *next = cur->next;
		cur->next = pre;
		pre = cur;
		cur = next;
	}
	head->next = pre;
}

int main()
{
	// 1.创建链表
	Node *head = createTail();

	// 2.反转链表所有结点
	reverseList(head);

	// 3.打印输出链表
	printList(head);
	
	// 4.释放链表
	freeList(head);
	return 0;
}

11.合并两个有序链表(升序):Node *mergeList(Node *h1, Node *h2);

Node *mergeList(Node *h1, Node *h2)
{
	Node *head = new Node();
	Node *p = head, *a = h1->next, *b = h2->next;

	while (a && b)
	{
		if ( a->data <= b->data )
		{
			p->next = a;
			a = a->next;
		}
		else
		{
			p->next = b;
			b = b->next;
		}
		p = p->next;
	}

	p->next = a ? a : b; // 剩余部分直接接到链表尾部

	h1->next = h2->next = nullptr;//原链表不再使用

	return head;
}

int main()
{
	// 1.创建两个有序链表
	Node *head1 = createTail();
	Node *head2 = createTail();

	// 2.合并两个有序链表
	Node *head = mergeList(head1, head2);
	// head1 和 head2不再有数据

	// 3.打印输出链表
	printList(head);

	// 4.释放链表
	freeList(head);
	return 0;
}

12.单链表排序(冒泡排序):void sortList(Node *head);

void bubbleSortList(Node *head)
{
	if (!head->next || !head->next->next)
		return;

	Node *last = nullptr;
	while ( head->next != last)
	{
		Node *p = head;
		while (p->next->next != last)
		{
			if (p->next->data > p->next->next->data)
			{
				//只交换数据,不改动指针
				/*
				int t = p->next->data;
				p->next->data = p->next->next->data;
				p->next->next->data = t;
				*/
				swap(p->next->data, p->next->next->data);
			}
			p = p->next;
		}
		last = p->next;
	}

}

int main()
{
	// 1.创建两个有序链表
	Node *head = createTail();

	// 2.链表排序(冒泡)
	bubbleSortList(head);

	// 3.打印输出链表
	printList(head);

	// 4.释放链表
	freeList(head);
	return 0;
}

13.单链表排序(归并排序):static Node *mergeSortCore(Node *first);

// 内嵌递归函数:对不带头结点的子链表进行归并排序,返回排序后的首结点
static Node *mergeSortCore(Node *first)
{
	if (!first || !first->next)
		return first;

	// 快慢指针找中点
	Node *slow = first, *fast = first->next;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	Node *mid = slow->next;
	slow->next = nullptr;            // 断开

	Node *left = mergeSortCore(first);
	Node *right = mergeSortCore(mid);

	// 合并两个有序子链表
	Node dummy, *cur = &dummy;
	while (left && right)
	{
		if (left->data <= right->data)
		{
			cur->next = left;
			left = left->next;
		}
		else
		{
			cur->next = right;
			right = right->next;
		}
		cur = cur->next;
	}
	cur->next = left ? left : right;
	return dummy.next;
}

void mergeSortList(Node *head)
{
	if (!head->next || !head->next->next)
		return;
	head->next = mergeSortCore(head->next);
}

int main()
{
	// 1.创建两个有序链表
	Node *head = createTail();

	// 2.链表排序(冒泡)
	mergeSortList(head);
编辑文章





C++单向(循环)链表操作模板
· 文章
Ctrl+K
	// 3.打印输出链表
	printList(head);

	// 4.释放链表
	freeList(head);
	return 0;
}

下面给出一个用类封装的单链表操作:

#include <bits/stdc++.h>
using namespace std;

// 单链表结点定义
struct Node
{
	int data;
	Node *next;
	Node(int x = 0): data(x), next(nullptr) {};
};

class SLinkedList
{
	private:
		Node *head;
	public:
		SLinkedList()
		{
			head = new Node();
		}

		// 尾插法创建链表(用数组)
		void createListTail(const int arr[], int n)
		{
			Node *tail = head;
			for (int i = 0; i < n; i++)
			{
				tail->next = new Node(arr[i]);
				tail = tail->next;
			}
		}
		// 打印输出链表(横向,空格分隔)
		void printList ()const
		{
			Node *p = head->next;
			if (!p)
				return;
			printf("%d", p->data);
			p = p->next;

			while (p)
			{
				printf(" %d", p->data);
				p = p->next;
			}
			printf("\n");
		}

		// 返回头结点
		Node *getHead ()const
		{
			return head;
		}

		// 返回第 i 个结点的指针(头结点为第0个,第1个为首元结点)
		Node *getAt(int i)const
		{
			if (i < 0)
				return nullptr;

			Node *p = head;
			int pos = 0;

			while (p && pos < i)
			{
				p = p->next;
				pos++;
			}
			return p;// p 可能为 nullptr(i 越界)
		}

		// 查找值为 x 的结点,返回其指针,若不存在返回 nullptr
		Node *findNode(int x) const
		{
			Node *p = head->next;
			while (p)
			{
				if (p->data == x)
					return p;
				p = p->next;
			}
			return nullptr;
		}

		// 返回值为x的结点指针
		Node *findPrev(int x)const
		{
			Node *p = head;
			while (p->next)
			{
				if (p->next->data == x)
					return p;
				p = p->next;
			}

			return nullptr;
		}

		// 在p之后插入结点e
		void insertAfter(Node *p, int e)
		{
			if (!p)
				return;
			Node *newNode = new Node(e);
			newNode->next = p->next;
			p->next = newNode;
		}

		// 删除p之后的结点
		bool delAfter(Node *p)
		{
			if (!p || !p->next)
				return false;
			Node *q = p->next;
			p->next = q->next;
			delete q;

			return true;
		}

		// 判断链表是否为空
		bool isEmpty() const
		{
			return head->next == nullptr;
		}
};

int main()
{
	SLinkedList list;
	int nums[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

	// 1.创建链表
	list.createListTail(nums, 10);

	// 2.打印输出链表
	printf("链表:");
	list.printList();

	// 3. 第 i 个元素后插入 e
	int i = 3, e = 99;
	Node *p = list.getAt(i);
	list.insertAfter(p, e);

	printf("插入后:");
	list.printList();

	// 4.删除第 n 个元素
	int n;
	cout << "输出要删除元素的位置:";
	cin >> n;
	p = list.getAt(n - 1); //获取第n-1个元素
	if (p)
		list.delAfter(p);
	else
		cout << "删除位置无效" << endl;

	printf("删除后:");
	list.printList();


	return 0;
}

单向循环链表
1.定义

单向循环链表是一种特殊的链表结构,其中最后一个节点的指针(或引用)不是指向空值(NULL),而是指向链表的头节点,从而形成一个环状或循环的结构。其最显著的优点是:从任一结点出发都可访问到表中所有结点,无需从头开始。

2.单向循环链表基础操作
(1)初始化。空链表仅存头结点,自身成环。
Node* head = new Node();
head->next = head;

(2)判空
bool isEmpty(Node* head)
{
return head->next == head;
}

(3)遍历。终止条件:指针回到头结点,防止死循环。
void traverse(Node* head)
{
Node* p = head->next;
while(p != head)
{
cout<val<<” “;
p = p->next;
}
}

(4)尾插法。找到尾节点(p->next==head)再插入。
void pushBack(Node* head, int x)
{
Node* p = head;
while(p->next != head) p = p->next;

Node* newNode = new Node(x);
p->next = newNode;
newNode->next = head;
}

(5)指定节点后插入。插入逻辑和普通单链表一致,仅边界闭环。
void insertAfter(Node* pos, int x)
{
Node* newNode = new Node(x);
newNode->next = pos->next;
pos->next = newNode;
}

(6)删除指定值节点。遍历找前驱,闭环重新衔接。
void delNode(Node* head, int x)
{
if(isEmpty(head)) return;
Node* p = head, *q;
while(p->next != head && p->next->val != x)
p = p->next;

if(p->next == head) return; // 无目标节点
q = p->next;
p->next = q->next;
delete q;
}

(7)清空链表。逐个释放节点,最后恢复空环。
void clear(Node* head)
{
Node* p = head->next, *q;
while(p != head)
{
q = p->next;
delete p;
p = q;
}
head->next = head;
}

单向循环链表和单向链表的区别:
(1)初始化
普通head->next=nullptr
循环head->next=head
(2)判空
普通:head->next == nullptr
循环:head->next == head
(3)遍历终止条件
普通:p != nullptr
循环:p != head
(4)尾节点判断
普通:p->next==nullptr
循环:p->next==head

下面给出类封装的单向链表操作:

#include <bits/stdc++.h>
using namespace std;

// 单链表节点
struct Node
{
	int data;
	Node *next;
	Node(int x = 0) : data(x), next(nullptr) {}
};

// 单向链表类
class SingleLinkList
{
	private:
		Node *head; // 带头哑结点
	public:
		// 构造初始化
		SingleLinkList()
		{
			head = new Node();
			head->next = nullptr;
		}

		// 析构释放
		~SingleLinkList()
		{
			clear();
			delete head;
		}

		// 头插法批量建表
		void createHead(int arr[], int n);
		// 尾插法批量建表
		void createTail(int arr[], int n);
		// 在pos节点后方插入元素x
		void insertAfter(Node *pos, int x);
		// 删除指定节点
		void delNode(Node *cur);
		// 查找值为x的节点,找不到返回nullptr
		Node *find(int x);
		// 正向遍历输出
		void traverse();
		// 获取链表有效长度
		int getLength();
		// 清空所有有效节点
		void clear();
		// 获取头结点
		Node *getHead();
};

// 头插建表
void SingleLinkList::createHead(int arr[], int n)
{
	clear();
	for (int i = 0; i < n; ++i)
		insertAfter(head, arr[i]);
}

// 尾插建表
void SingleLinkList::createTail(int arr[], int n)
{
	clear();
	Node *tail = head;
	for (int i = 0; i < n; ++i)
	{
		insertAfter(tail, arr[i]);
		tail = tail->next;
	}
}

// 指定节点后插入
void SingleLinkList::insertAfter(Node *pos, int x)
{
	if (!pos)
		return;
	Node *newNode = new Node(x);
	newNode->next = pos->next;
	pos->next = newNode;
}

// 删除指定节点
void SingleLinkList::delNode(Node *cur)
{
	if (!cur || cur == head)
		return;
	Node *p = head;
	// 查找前驱节点
	while (p && p->next != cur)
		p = p->next;
	if (!p)
		return;
	p->next = cur->next;
	delete cur;
}

// 按值查找
Node *SingleLinkList::find(int x)
{
	Node *p = head->next;
	while (p)
	{
		if (p->data == x)
			return p;
		p = p->next;
	}
	return nullptr;
}

// 遍历打印
void SingleLinkList::traverse()
{
	Node *p = head->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

// 统计长度
int SingleLinkList::getLength()
{
	int len = 0;
	Node *p = head->next;
	while (p)
	{
		len++;
		p = p->next;
	}
	return len;
}

// 清空链表
void SingleLinkList::clear()
{
	Node *p = head->next, *q;
	while (p)
	{
		q = p->next;
		delete p;
		p = q;
	}
	head->next = nullptr;
}

// 获取头结点
Node *SingleLinkList::getHead()
{
	return head;
}

// 测试用例
int main()
{
	SingleLinkList slist;
	int a[] = {1, 2, 3, 4, 5};
	int n = sizeof(a) / sizeof(int);

	slist.createTail(a, n);
	cout << "初始链表:";
	slist.traverse();
	cout << "链表长度:" << slist.getLength() << endl;

	Node *pos = slist.find(3);
	if (pos)
		slist.insertAfter(pos, 6);
	cout << "插入元素后:";
	slist.traverse();

	slist.delNode(pos);
	cout << "删除节点后:";
	slist.traverse();

	slist.clear();
	cout << "清空后长度:" << slist.getLength() << endl;

	return 0;
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

标签云