C++构建链表

C++构建链表

  • 代码
    • 头文件
    • 主程序(测试)
  • 定义链表节点
  • 构造链表类
    • 定义类成员
    • 构造函数
    • 成员函数
      • get()
      • addAtHead()
      • addAtTail()
      • addAtIndex()
      • deleteAtIndex()
      • reverseList()
      • 打印链表的函数(非成员函数)

代码

头文件

LinkList.h

#ifndef LINKLIST_H
#define LINKLIST_H

#include 
#include 

class LinkList {
	friend std::ostream &operator<<(std::ostream &out, const LinkList &L);
	friend LinkList* link2node2link(LinkList *obj);

public:
    struct ListNode {
        int val;
        ListNode *next;
        ListNode() : val(0), next(nullptr) {}
        ListNode(int x) : val(x), next(nullptr) {}
        ListNode(int x, ListNode* next) : val(x), next(next) {}
    };

    LinkList() {
        _dummyHead = new ListNode(0);
        _len = 0;
    }
    
	int get(int index) const;				// 取得链表第index个数的值
	void addAtHead(int val);				// 头插法
	void addAtTail(int val);				// 尾插法
	void addAtIndex(int index, int val);	// 在第index个数之后插入
	void deleteAtIndex(int index);			// 删除第index个数
	void reverseList();						// 反转链表

private:
    ListNode *_dummyHead;
    unsigned _len = 0;
};

int LinkList::get(int index) const {
    if (index < 0 || index > (_len - 1)) return -1;
    ListNode *cur = _dummyHead->next;
    while (index--) {
        cur = cur->next;
    }
    return cur->val;
}

void LinkList::addAtHead(int val) {
    ListNode *newNode = new ListNode(val);	// 用val创建新节点
    newNode->next = _dummyHead->next;		
    _dummyHead->next = newNode;
    ++_len;									// 注意增加链表长度
}

void LinkList::addAtTail(int val) {
    ListNode *newNode = new ListNode(val);
    ListNode *cur = _dummyHead;
    while (cur->next) {			// 遍历到表尾
        cur = cur->next;
    }
    cur->next = newNode;
    ++_len;						// 注意增加链表长度
}

void LinkList::addAtIndex(int index, int val) {
    if (index < 0 || index > _len) return;		// 判断是否超出范围
    ListNode *newNode = new ListNode(val);
    ListNode *cur = _dummyHead;
    while (index--) {
        cur = cur->next;
    }
    newNode->next = cur->next;
    cur->next = newNode;
    ++_len;
}

void LinkList::deleteAtIndex(int index) {
    if (index < 0 || index > (_len - 1)) return;
    ListNode *cur = _dummyHead;
    while (index--) {
        cur = cur->next;
    }
    ListNode *tmp = cur->next;
    cur->next = cur->next->next;
    delete tmp;
    --_len;				// 注意删除后减小链表长度
}

void LinkList::reverseList() {
	ListNode *cur = _dummyHead->next;	// 从头节点出发
    ListNode *node = nullptr;			// 上一个节点
    while (cur) {
        LinkList::ListNode *tail = cur->next;	// 保存下一个节点
        cur->next = node;		// 当前节点的下一位变成上一个节点
        node = cur;				// 上一个节点后移
        cur = tail;				// 跳到原链表中下一个需要处理的节点
    }
    _dummyHead->next = node;
}

std::ostream &operator<<(std::ostream &out, const LinkList &L) {
	LinkList::ListNode *p = L._dummyHead->next;
	while (p) {
		out << p->val << "->";
		p = p->next;
	}
	// 输出样式 1->2->3
	out << "\b\b  ";  // 删除最后的->,最后一个\b后有两个空格
	return out;
}

// 将容器中的数值使用尾插法添加到链表中
void vector2list(const std::vector<int> &vec, LinkList *obj) {
	if (vec.empty()) {
		return;
	}
	
	for (const auto &i : vec) {
		obj->addAtTail(i);
	}

	return;
}

#endif // LINKLIST_H

主程序(测试)

LinkList.cpp

#include 
#include 
#include "LinkList.h"

using namespace std;

int main()
{
    vector<int> list = {1, 2, 2, 3, 4, 5, 3, 3, 3, 4, 5};
    LinkList *obj = new LinkList();
    vector2list(list, obj);
    
    cout << "构建链表:" << endl;
    cout << *obj << endl;
    
    cout << "链表第2个节点的值为:";
    cout << obj->get(2) << endl;
    
    cout << "头插法,在链表之前插入0:" << endl;
    obj->addAtHead(0);
    cout << *obj << endl;
    
	cout << "尾插法,在链表末尾插入0:" << endl;
    obj->addAtTail(0);
    cout << *obj << endl;

	cout << "在第一个节点后插入99:" << endl;
    obj->addAtIndex(1, 99);
    cout << *obj << endl;
    
	cout << "删除第一个元素:" << endl;
    obj->deleteAtIndex(0);
    cout << *obj << endl;

    cout << "反转链表:" << endl;
    obj->reverseList();
    cout << *obj << endl;

    return 0;
}

定义链表节点

struct ListNode {
        int val;
        ListNode *next;
        ListNode() : val(0), next(nullptr) {}
        ListNode(int x) : val(x), next(nullptr) {}
        ListNode(int x, ListNode* next) : val(x), next(next) {}
};

构造链表类

定义类成员

链表有两个成员变量:一个伪头节点_dummyHead和链表长度_len

Class LinkList {
Private:
	ListNode *_dummyHead;
	unsigned _len = 0;
}

构造函数

构造头节点之前的伪头节点_dummyHead方便进行头插法

LinkList() {
	_dummyHead = new ListNode(0);
	_len = 0;
}

成员函数

链表包含:取值,插入元素,删除元素和反转链表的功能。

int get(int index) const;				// 取得链表第index个数的值
void addAtHead(int val);				// 头插法
void addAtTail(int val);				// 尾插法
void addAtIndex(int index, int val);	// 在第index个数之后插入
void deleteAtIndex(int index);			// 删除第index个数
void reverseList();						// 反转链表
// 输出链表值
friend std::ostream &operator<<(std::ostream &out, const LinkList &L);

get()

  • 功能:输出链表第n个数的值;
  • 输入:索引;
  • 输出:对应索引节点的值。
int LinkList::get(int index) const {
    if (index < 0 || index > (_len - 1)) return -1;
    ListNode *cur = _dummyHead->next;
    while (index--) {
        cur = cur->next;
    }
    return cur->val;
}

首先判断index是否在链表范围内,若不在返回 -1

addAtHead()

  • 功能:在链表表头添加元素;
  • 输入:插入数值;
  • 输出:无。
// 头插法
void LinkList::addAtHead(int val) {
    ListNode *newNode = new ListNode(val);	// 用val创建新节点
    newNode->next = _dummyHead->next;		
    _dummyHead->next = newNode;
    ++_len;									// 注意增加链表长度
}

一定注意要增加链表长度 _len

addAtTail()

  • 功能:在链表表尾添加元素;
  • 输入:插入数值;
  • 输出:无。
// 尾插法
void LinkList::addAtTail(int val) {
    ListNode *newNode = new ListNode(val);
    ListNode *cur = _dummyHead;
    while (cur->next) {			// 遍历到表尾
        cur = cur->next;
    }
    cur->next = newNode;
    ++_len;						// 注意增加链表长度
}

addAtIndex()

  • 功能:在索引后添加元素;
  • 输入:
    • 索引;
    • 插入数值;
  • 输出:无。
void LinkList::addAtIndex(int index, int val) {
    if (index < 0 || index > _len) return;		// 判断是否超出范围
    ListNode *newNode = new ListNode(val);
    ListNode *cur = _dummyHead;
    while (index--) {
        cur = cur->next;
    }
    newNode->next = cur->next;
    cur->next = newNode;
    ++_len;
}

if (index < 0 || index > _len)中上限宽松了一位,因为在_index - 1处也可以插入元素。

deleteAtIndex()

  • 功能:删除索引处元素;
  • 输入:索引;
  • 输出:无。
void LinkList::deleteAtIndex(int index) {
    if (index < 0 || index > (_len - 1)) return;
    ListNode *cur = _dummyHead;
    while (index--) {
        cur = cur->next;
    }
    ListNode *tmp = cur->next;
    cur->next = cur->next->next;
    delete tmp;
    --_len;				// 注意删除后减小链表长度
}

reverseList()

  • 功能:反转链表;
  • 输入:无;
  • 输出:无。
void LinkList::reverseList() {
	ListNode *cur = _dummyHead->next;	// 从头节点出发
    ListNode *node = nullptr;			// 上一个节点
    while (cur) {
        LinkList::ListNode *tail = cur->next;	// 保存下一个节点
        cur->next = node;		// 当前节点的下一位变成上一个节点
        node = cur;				// 上一个节点后移
        cur = tail;				// 跳到原链表中下一个需要处理的节点
    }
    _dummyHead->next = node;
}

打印链表的函数(非成员函数)

  • 功能:打印链表的值;
  • 输入:
    • 输出流out
    • 链表
  • 输出:输出流。
std::ostream &operator<<(std::ostream &out, const LinkList &L) {
	LinkList::ListNode *p = L._dummyHead->next;
	while (p) {
		out << p->val << "->";
		p = p->next;
	}
	// 输出样式 1->2->3
	out << "\b\b  ";  // 删除最后的->,最后一个\b后有两个空格
	return out;
}

重载<<。注意 "\b\b " 后有两个空格。

你可能感兴趣的:(C++,链表,c++,数据结构)