c++实现单向链表

一、链表知识点:

1.概念:

链表作为一种线性数据结构,跟数组的区别在于数组是连续的存储单元,而链表是离散的。链表使用节点来对数据进行存储,一个数据存储在一个节点中,节点之间通过指针相连,所以一个节点分为数据域(data)和指针域(next),数据域负责存储用户数据,指针域负责链接节点。

2.分类:

Ⅰ:单链表

        每个结点除了存储数据data外,还需要记录下个结点的地址,称为后继指针next。

Ⅱ:双向链表

        每个结点除了存储数据data外,还会会记录上一个结点和下一个结点的地址。

Ⅲ:循环列表

        循环链表的尾结点不指向空,而是指向头结点,类似一个环形结构。

3.特点:

Ⅰ:由于链表的内存空间是零散的,所以不支持随机访问。

Ⅱ:插入、删除不需要移动数据,所以效率高。

Ⅲ:因为链表的每个内存块都不是连续的,所以不需要提前计算内存的大小,内存空间可以根据结点数量的改变而改变。

4.头节点用处:

Ⅰ:便于首元结点的处理
首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其他位置一致,无须进行特殊处理。
Ⅱ:便于空表和非空表的统一处理
无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。

二、c++实现单向链表(全部代码附在最后)

1.利用c++实现单向链表,首先构建节点类:

#include<iostream>
#include<string>
using namespace std;

//构建节点类
class NODE {
public:
	NODE* pnext;
	int data;
};

2.然后构建链表类,链表类应该继承节点的属性,并添加头节点和链表长度属性:

class LINK : public NODE{
public:
	//初始化头节点和链表长度
	LINK() {
		head = new NODE();
		len = 0;
	};
    
   //对堆区的数据进行释放,释放时需要创建两个临时节点保存数据,否则前一个释放以后找不到后一个节点
	~LINK() {
		NODE* t = head;
		NODE* r = head->pnext;
		if (r != nullptr) {
			delete t;
			t = r;
			r = r->pnext;
		}
		delete t;
	};

//定义头节点和链表长度
private:
	NODE* head;
	int len;
};

3.在类中实现链表判空(empty)、尾插(append)、中间插入(insert)、删除(del)、降序排列(sort)、求链表长度(length)、遍历输出(travel)等算法

判空:只需判定len属性是否为0

	bool empty() {
		if (len == 0) return true;
		else return false;
	}

尾插:

	void append() {
		NODE* t = head; //始终指向尾节点,用于修改每个节点的指针域,初始化指向头节点
		NODE* r; //新增的数据节点

		int n;
		cout << "请输入整型数据,以空格分开,以0结尾:";
		while (cin >> n, n != 0) {
			r = new NODE();
			r->data = n;
			t->pnext = r;
			t = r;
			len++;
		}
		t->pnext = nullptr;
	};

中间插入(insert):

void insert(int val, int pos) {
		NODE* r; NODE* s; NODE* t;
		s = head->pnext;
		for (int i = 0; i < pos-1; i++) {
			s = s->pnext;
		}
		r = new NODE();
		r->data = val;
		t = s->pnext;
		s->pnext = r;
		r->pnext = t;
		len++;
		return;
	};

删除(del)(删除pos位置处节点):

	void del(int pos) {
		NODE* r; NODE* s; NODE* t;
		s = head->pnext;
		for (int i = 0; i < pos - 1; i++) {
			s = s->pnext;
		}
		t = s->pnext->pnext;
		delete s->pnext;
		s->pnext = t;
		len--;
		return;

	};

链表降序排列:

	void sort() {
		NODE* r; NODE* s;
		r = head->pnext;
		for (r; r->pnext!=nullptr;r=r->pnext) {
			//错误写法:for (s=r->pnext; s->pnext!= nullptr; s=s->pnext)
			//上述写法无法对尾节点操作,因为直接判定尾节点为空就不进入循环了
			for (s=r->pnext; s!= nullptr; s=s->pnext) {
				if (r->data < s->data) {
					int x = r->data;
					r->data = s->data;
					s->data = x;
				}
			}
		}
		return;
	};

求链表长度:

	void length() {
		cout << "链表长度为:" << len << endl;
		return;
	};

遍历输出链表:

	void travel() {
		NODE* p = head->pnext;
		//错误写法:while (p->next!=nullptr)  会导致输出不了最后一个节点
		//上述写法表示如果这个节点指针域不为空,就打印此节点的数据域,然而最后一个节点指针域是空的
		while (p != nullptr) {
			cout << p->data << " ";
			p = p->pnext;
		}
		cout << endl;
		return;
	};

4.测试:

void test() {
	LINK link;
	link.append();
	cout << "尾插法初始化链表为: ";
	link.travel();
	link.insert(10, 2);
	cout << "插入后链表为: ";
	link.travel();
	link.del(3);
	cout << "删除后链表为: ";
	link.travel();
	link.sort();
	cout << "降序排列后链表为: ";
	link.travel();
	link.length();

	return;
}

5.效果:

 三:全部代码:

#include<iostream>
#include<string>
using namespace std;


class NODE {
public:
	NODE* pnext;
	int data;
};

class LINK : public NODE{
public:
	//初始化头节点和链表长度
	LINK() {
		head = new NODE();
		len = 0;
	};

	//对堆区的数据进行释放,释放时需要创建两个临时节点保存数据,否则前一个释放以后找不到后一个节点
	~LINK() {
		NODE* t = head;
		NODE* r = head->pnext;
		if (r != nullptr) {
			delete t;
			t = r;
			r = r->pnext;
		}
		delete t;
	};

	//判空
	bool empty() {
		if (len == 0) return true;
		else return false;
	}

	//尾插法添加节点,也需要创建两个临时节点
	void append() {
		NODE* t = head; //始终指向尾节点,用于修改每个节点的指针域,初始化指向头节点
		NODE* r; //新增的数据节点

		int n;
		cout << "请输入整型数据,以空格分开,以0结尾:";
		while (cin >> n, n != 0) {
			r = new NODE();
			r->data = n;
			t->pnext = r;
			t = r;
			len++;
		}
		t->pnext = nullptr;
	};

	//链表插入(在pos位置前插入)
	void insert(int val, int pos) {
		NODE* r; NODE* s; NODE* t;
		s = head->pnext;
		for (int i = 0; i < pos-1; i++) {
			s = s->pnext;
		}
		r = new NODE();
		r->data = val;
		t = s->pnext;
		s->pnext = r;
		r->pnext = t;
		len++;
		return;
	};

	//链表删除(删除pos位置处节点)
	void del(int pos) {
		NODE* r; NODE* s; NODE* t;
		s = head->pnext;
		for (int i = 0; i < pos - 1; i++) {
			s = s->pnext;
		}
		t = s->pnext->pnext;
		delete s->pnext;
		s->pnext = t;
		len--;
		return;

	};

	//链表排序
	void sort() {
		NODE* r; NODE* s;
		r = head->pnext;
		for (r; r->pnext!=nullptr;r=r->pnext) {
			//错误写法:for (s=r->pnext; s->pnext!= nullptr; s=s->pnext)
			//上述写法无法对尾节点操作,因为直接判定尾节点为空就不进入循环了
			for (s=r->pnext; s!= nullptr; s=s->pnext) {
				if (r->data < s->data) {
					int x = r->data;
					r->data = s->data;
					s->data = x;
				}
			}
		}
		return;
	};

	void travel() {
		NODE* p = head->pnext;
		//错误写法:while (p->next!=nullptr)  会导致输出不了最后一个节点
		//上述写法表示如果这个节点指针域不为空,就打印此节点的数据域,然而最后一个节点指针域是空的
		while (p != nullptr) {
			cout << p->data << " ";
			p = p->pnext;
		}
		cout << endl;
		return;
	};

	void length() {
		cout << "链表长度为:" << len << endl;
		return;
	};

private:
	NODE* head;
	int len;
};



void test() {
	LINK link;
	link.append();
	cout << "尾插法初始化链表为: ";
	link.travel();
	link.insert(10, 2);
	cout << "插入后链表为: ";
	link.travel();
	link.del(3);
	cout << "删除后链表为: ";
	link.travel();
	link.sort();
	cout << "降序排列后链表为: ";
	link.travel();
	link.length();

	return;
}

void main() {
	test();
	return;
}

猜你喜欢

转载自blog.csdn.net/qq_43575504/article/details/129798054
今日推荐