链表

第2章 算法复杂度

算法的时间复杂度定义(大O记法)

语句总执行次数T(N)跟问题规模N的函数,时间复杂度记作:T(N) = O(f(N)),表达随着问题规模的增大,算法执行时间的增长率和f(N)的增长率相同,f(N)是问题规模N的某个函数。

O(1):常数阶 O(N):线性阶 O(N^2):平方阶

 总结:参考大话数据结构第二章小节

第3章 线性表

3.2 线性表的定义

线性表:零个或多个元素的有限序列(有序,有前驱,有后继)

3.3 线性表的顺序存储结构

用一段地址连续的存储单元依次存储线性表的数据元素

3.4 线性表的链式存储结构

数据域:存储数据元素信息的域

指针域:存储直接后置位置的域

结点:包括数据域和指针域

头指针:链表第一个结点的存储位置(一定不为空,链表的必要元素)

头结点:在第一个结点前设的节点,其指针域存储指向第一个节点的指针(若链表有头结点,头指针是指向头结点的指针)(有了头结点,就可以对链表第一元素进行删除操作或者插入操作)

 

 

//链表结点定义
struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x) : val(x), next(NULL) {}
};

 删除链表的节点:

版本1:val: int 解法O(N)/O(1)使用头结点
版本2:val: ListNode 解法:信息交换法O(1)/O(1)

/*版本1:val: int 解法O(N)/O(1)
版本2:val: ListNode 解法:信息交换法O(1)/O(1)
*/

class Solution {
public:
	//使用头结点,万一要删除第一结点n

	ListNode* deleteNode(ListNode* head, int val) {
		ListNode* dummyNode = new ListNode(0);
		dummyNode->next = head;
		ListNode* cur = dummyNode;
		while (cur != NULL && cur->next != NULL) {  //注意先判断cur != NULL,再判断cur->next != NULL
			//遇到则删除该结点
			if (cur->next->val == val) {
				cur->next = cur->next->next;
			}
			cur = cur->next;
		}
		return dummyNode->next;
	}
	//val: ListNode 解法:信息交换法
	//当输入参数为删除的结点时,可以采用信息交换,即deleteNode->val = deleteNode->next->val; deleteNode->next = deleteNode->next->next;
	//当删除结点不在尾结点时,可以实现常数时间删除
	//当删除结点是尾结点,无法找到尾结点的后一元素,所以需要从头遍历
	//时间复杂度:(O(1)*(N - 1) + 0(N))/N = O(1)

	ListNode* deleteNode2(ListNode* head, ListNode* deleteNode) {
		if (head == NULL || deleteNode == NULL) return NULL;
		if (deleteNode->next != NULL) {
			deleteNode->val = deleteNode->next->val;
			deleteNode->next = deleteNode->next->next;
		}
		//头尾结点相同
		else if (head == deleteNode) return NULL;
		else {
			ListNode* cur = head;
			//找到倒数第二结点
			while (cur->next != NULL && cur->next->next != NULL) {
				cur = cur->next;
			}
			cur->next = NULL;
		}
		return head;
	}
};

链表设计:

版本1:单向表
版本2:双向表


/*
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:


	get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
	addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
	addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
	addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
	deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。


*/

//执行用时:40 ms, 在所有 C++ 提交中击败了98.40%的用户
//内存消耗 :19.3 MB, 在所有 C++ 提交中击败了21.27%的用户
class MyLinkedList {
private:
	//单链表版本
	struct ListNode {
		int val;
		ListNode* next;
		ListNode(int x) :val(x), next(NULL) {}
	};
	ListNode* head;
public:
	MyLinkedList() :head(NULL) {
	}

	//获取链表中第index个结点的值
	int get(int index) {
		ListNode* cur = head;
		int i = 0;
		while (cur && i < index) {
			cur = cur->next;
			++i;
		}
		//不是末尾
		if (cur) return cur->val;
		else return -1;
	}

	//在头结点前面新增结点
	void addAtHead(int val) {
		ListNode* newHead = new ListNode(val);
		newHead->next = head;
		head = newHead;   //指向第一个结点
	}
	//在链表末尾添加元素
	/** Append a node of value val to the last element of the linked list. */
	void addAtTail(int val) {
		//链表为空,直接将新节点作为头结点
		ListNode* p = new ListNode(val);
		if (!head) {
			head = p;
			return;
		}
		//链表不为空,则在尾部添加,找到尾结点
		ListNode* cur = head;
		while (cur->next) {
			cur = cur->next;
		}
		cur->next = p;
	}

	//在链表中第index个结点之前添加值为val的结点
	void addAtIndex(int index, int val) {
		ListNode* p = new ListNode(val);
		if (index <= 0) {
			addAtHead(val);  //index <= 0, 在头部插入
			return;
		}
		ListNode* cur = head;
		int i = 0;
		//获得第index - 1个结点
		while (cur && i < index - 1) {
			cur = cur->next;
			++i;
		}
		//一种是cur == NULL,说明超出尾结点,不添加
		//另一种是cur != NULL,添加结点(包括)
		if (cur) {
			p->next = cur->next;
			cur->next = p;
		}

	}

	//删除第index个结点
	void deleteAtIndex(int index) {
		if (head == NULL || index < 0) return;
		if (index == 0) {
			head = head->next;
			return;
		}
		ListNode* cur = head;
		int i = 0;
		//找到第index - 1个元素
		while (cur && i < index - 1) {
			cur = cur->next;
			++i; //用前置++更好
		}
		if (cur) {
			//如果index - 1是最后一个结点
			if (!cur->next) return;
			else {
				cur->next = cur->next->next;
			}
		}
	}
	//计算链表长度
	int length() {
		int i = 0;
		ListNode* cur = head;
		while (cur) {
			++i;
			cur = cur->next;
		}
		return i;
	}
};


//双向链表版
class MyLinkedList {
private:
	struct ListNode {
		int val;
		ListNode* next;
		ListNode* prev;
		ListNode(int x) :val(x), prev(NULL), next(NULL) {}
	};
	ListNode* head;
	ListNode* tail;
	int size;
public:
	MyLinkedList() :size(0), head(NULL), tail(NULL) {
	}

	//获取链表中第index个结点的值
	int get(int index) {
		ListNode* cur = head;
		int i = 0;
		while (cur && i < index) {
			cur = cur->next;
			++i;
		}
		//不是末尾
		if (cur) return cur->val;
		else return -1;
	}

	//在头结点前面新增结点
	void addAtHead(int val) {
		ListNode* newHead = new ListNode(val);
		if (head) {
			newHead->next = head;
			head->prev = newHead;
			head = newHead;   //重定位head

		}
		else {
			//如果头尾结点都不存在
			head = tail = newHead;

		}
		++size; //累计数量
	}
	//在链表末尾添加元素
	/** Append a node of value val to the last element of the linked list. */
	void addAtTail(int val) {
		//链表不为空,直接将新节点作为头结点
		ListNode* p = new ListNode(val);
		if (tail) {
			tail->next = p;
			p->prev = tail;
			tail = p;   //重定位tail
		}
		else {
			tail = head = p;
		}
		++size;
	}

	//在链表中第index个结点之前添加值为val的结点
	void addAtIndex(int index, int val) {
		ListNode* p = new ListNode(val);
		if (index <= 0) {
			addAtHead(val);  //index <= 0, 在头部插入
			return;
		}
		if (index == size) {
			addAtTail(val);
			return;
		}
		if (index > size) return;
		//寻找第index个结点cur,记录前面一个结点before,before->next = p...
		ListNode* cur = head;
		ListNode* b = NULL;
		int i = 0;
		while (cur && i < index) {
			b = cur;
			cur = cur->next;
			++i;
		}
		if (cur) {
			b->next = p;
			p->prev = b;
			p->next = cur;
			cur->prev = p;
			++size;
		}
	}

	//删除第index个结点
	void deleteAtIndex(int index) {
		//如果索引不在范围内,不作处理
		if (index < 0 || index > size - 1) return;
		//如果删除头结点
		if (index == 0) {
			head = head->next;  //重定位head
			if (head) {
				head->prev = NULL;
			}
			else {
				tail = NULL; //重定位tail
			}
			--size;
			return;
		}
		//删除尾结点
		if (index == size - 1) {
			tail = tail->prev; //重定位尾结点
			//不用单结点,前面index = 0已经考虑过了
			tail->next = NULL;
			--size;
			return;
		}
		//删除中间结点,先找到索引为index的结点
		ListNode* b = NULL, *cur = head;
		int i = 0;
		while (cur && i < index) {
			b = cur;
			cur = cur->next;
			++i;
		}
		b->next = cur->next;
		cur->next->prev = b;
		--size;
	}
	//计算链表长度
	int length() {
		return size;
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值