0
点赞
收藏
分享

微信扫一扫

数据结构 【链表】部分功能实现

IT程序员 2022-03-18 阅读 60

一. 单链表的定义、插入与删除

1.定义一个单链表

typedef struct LNode
{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;

typedef <数据类型> <别名> 用别名来代替该数据类型名

LinkList为指向该单链表的指针。

2.初始化一个空的单链表,与判断单链表是否为空

1.不带头结点的单链表

bool InitList(LinkList &L)
{
	L = NULL;
	return true;
}

bool Empty(LinkList L)
{
	return (L == NULL);
}

2.带头结点的单链表

bool InitList(LinkList &L)
{
	L = (LNode*)malloc(sizeof(LNode));
	if (L == NULL)
		return false;
	L->next = NULL;
	return true;
}

bool Empty(LinkList L)
{
	return (L->next == NULL);
}

 3.按位序插入

1.带头结点

bool ListInsert(LinkList &L, int i, ElemType e)
{
	if (i < 1)
		return false;
	LNode *p;
	int j = 0;
	p = L;
	while (p != NULL && j < i - 1) //寻找插入位序的前一个节点
	{
		p = p->next;
		j++;
	}
	if (p == NULL)
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

 2.不带头结点

bool ListInsert(LinkList &L, int i, ElemType e)
{
	if (i < 1)
		return false;
	if (i == 1)
	{
		LNode *s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s; //头指针指向头节点
	}
	LNode *p;
	int j = 0;
	p = L;
	while (p != NULL && j < i - 1) //寻找插入位序的前一个节点
	{
		p = p->next;
		j++;
	}
	if (p == NULL)
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

 4.指定节点的插入操作

1.后插

bool InsertNextNode(LNode *p, ElemType e)
{
	if (p == NULL)
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)
		return false; //内存分配失败
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

2.前插

bool InsertPriorNode(LNode *p, ElemType e)
{
	if (p == NULL)
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)
		return false; //内存分配失败
	s->next = p->next;
	p->next = s;
	s->data = p->data;
	p->data = e;
	return true;
}

 5.按位序删除(带头结点)

bool ListDelete(LinkList &L, int i, ElemType &e)
{
	if (i < 1)
		return false;
	LNode *p;
	int j = 0;
	p = L;
	while (p != NULL && j < i - 1) //寻找插入位序的前一个节点
	{
		p = p->next;
		j++;
	}
	if (p == NULL)
		return false; //i值不合法
	if (p->next == NULL)
		return false; //第i-1个节点后已无其他节点
	LNode *q = p->next;
	e = q->data;
	p->next = q->next;
	free(q);
	return true;
}

 6.指定节点的删除

bool DeleteNode(LNode *p)
{
	if (p == NULL)
		return false;
	LNode *q = p->next;
	p->data = p->next->data;
	p->next = q->next;
	free(q);
	return true;
}

但如果p是最后一个节点,只能从表头以循环的方式寻找p的前驱节点。时间复杂度为O(n) 

二. 单链表的查找 

1.按位查找(带头结点)

LNode* GetElem(LinkList L, int i)
{
	if (i < 0)
		return NULL;
	LNode *p;
	int j = 0;
	p = L; //L指向头结点
	while (p != NULL && j < i)
	{
		p = p->next;
		j++;
	}
	return p;
}

2.按值查找(带头结点) 

LNode* LocateElem(LinkList L, ElemType e)
{
	LNode *p = L->next; //从第一个节点开始查找
	while (p != NULL && p->data != e)
		p = p->next;
	return p;
}

3.求表的长度(带头结点)

int Length(LinkList L)
{
	int len = 0;
	LNode *p = L;
	while (p->next != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}

三.单链表的建立

1.尾插法建立单链表

LinkList List_TailInsert(LinkList &L)
{
	int x;
	L = (LinkList)malloc(sizeof(LinkList));
	L->next = NULL;
	LNode *s, *r = L;
	cin >> x;
	while (x != 9999) //输入9999表示结束
	{
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = r->next;
		r->next = s;
		r = s;
		cin >> x;
	}
	r->next = NULL;
	return L;
}

2.头插法建立单链表

LinkList List_HeadInsert(LinkList &L)
{
	LNode *s;
	int x;
	L = (LinkList)malloc(sizeof(LinkList));
	L->next = NULL;
	cin >> x;
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	return L;
}

四.双链表

1.双链表的初始化与判空

typedef struct DNode
{
	ElemType data;
	struct DNode *prior, *next;
}DNode, *DLinklist;

bool InitDLinkList(DLinklist &L)
{
	L = (DNode*)malloc(sizeof(DNode));
	if (L == NULL)
		return false;
	L->prior = NULL;
	L->next = NULL;
	return true;
}
bool Empty(DLinklist L)
{
	if (L->next == NULL)
		return true;
	else
		return false;
}

判空其实能一行写完 

 2.在指定结点处后插新结点

bool InsertNextDNode(DNode *p, DNode *s)
{
	if (p == NULL || s == NULL) //非法参数
		return false;
	s->next = p->next;
	if (p->next != NULL) //如果p结点有后继结点
		p->next->prior = s;
	s->prior = p;
	p->next = s;
	return true;
}

3.删除指定结点的后继结点

bool DeleteNextDNode(DNode *p)
{
	if (p == NULL)
		return false;
	DNode *q = p->next; //找到p的后继结点
	if (q == NULL)
		return false;
	p->next = q->next;
	if (q->next != NULL) //q结点不是最后一个结点
		q->next->prior = p;
	free(q);
	return true;
}

4.销毁双链表

void DestoryList(DLinklist &L)
{
	while (L->next != NULL)
		DeleteNextDNode(L);
	free(L);
	L = NULL;
}

五.循环链表

1.循环单链表

(1)初始化

//初始化一个循环单链表
bool InitList(LinkList &L)
{
	L = (LNode*)malloc(sizeof(LNode));
	if (L == NULL)
		return false;
	L->next = L;
	return true;
}

(2)判断是否为空

//判断循环单链表是否为空
bool Empty(LinkList L)
{
	if (L->next == L)
		return true;
	else
		return false;
}

(3)判断p结点是否为尾结点

//判断结点p是否为循环单链表的尾结点
bool isTail(LinkList L, LNode *p)
{
	if (p->next == L)
		return true;
	else
		return false;
}

2.循环双链表

//初始化一个循环双链表
bool InitDLinkList(DLinklist &L)
{
	L = (DNode*)malloc(sizeof(DNode));
	if (L == NULL)
		return false;
	L->prior = L;
	L->next = L;
	return true;
}

这里就给出了其初始化操作,其余操作与双链表类似,而且很好写,就不列出了

六.相关题目

1.将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

建立一个指向指针的指针pp,两个链表的结点分别比较大小,小的先进入结果链表。

/**
 * Definition for singly-linked list.
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
     ListNode* dummy = new ListNode(0);
        ListNode* cur = dummy;
        while (list1 != nullptr && list2 != nullptr) 
        {
            ListNode** pp = (list1->val < list2->val) ? &list1 : &list2;
            cur->next = *pp;
            cur = cur->next;
            *pp = (*pp)->next;
        }
        cur->next = (list1 == nullptr) ? list2 : list1;

        ListNode* ans = dummy->next;
        delete dummy;
        return ans;
    }
};

2.给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

因为是已排序的链表,只需比较相邻两个结点即可。

/**
 * Definition for singly-linked list.
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head==NULL)
			return head;
		ListNode *s = head;
		while (s->next != NULL)
		{
			if (s->val == s->next->val)
				s->next = s->next->next;
			else
				s = s->next;
		}
		return head;
    }
};

3.给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

Floyd 判圈算法,用快慢指针可以就地解决。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head == NULL)
			 return nullptr;
		 ListNode *slowPtr = head, *fastPtr = head;
		 bool existPtr = false;
		 while (fastPtr->next != NULL && fastPtr->next->next != NULL)
		 {
			 slowPtr = slowPtr->next;
			 fastPtr = fastPtr->next->next;
			 if (slowPtr == fastPtr)
			 {
				 existPtr = true;
			 }
			 if (existPtr)
			 {
				 slowPtr = head;
				 while (slowPtr != fastPtr)
				 {
					 slowPtr = slowPtr->next;
					 fastPtr = fastPtr->next;
				 }
				 return slowPtr;
			 }
		 }
		 return nullptr;
    }
};

4.试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点唯一)。

用minp保存值最小的结点指针(初值为p)

LinkList Delete_Min(LinkList &L)
{
	LNode *pre = L, *p = pre->next;
	LNode *minpre = pre, *minp = pre;
	while (p != NULL)
	{
		if (p->data < minp->data)
		{
			minp = p;
			minpre = pre;
		}
		pre = p;
		p = p->next;
	}
	minpre->next = minp->next;
	free(minp);
	return L;
}

5.有一个带头结点的单链表L,设计一个算法使其元素递增有序。

采用直接插入排序的思想,先构成一个只含一个数据结点的有序单链表,然后依次扫描单链表中剩下的结点*p,通过比较找到前驱节点*pre,插入到*pre之后。

void Sort(LinkList &L)
{
	LNode *p = L->next, *pre;
	LNode *r = p->next;
	p->next = NULL;
	p = r;
	while (p != NULL)
	{
		r = p->next;
		pre = L;
		while (pre->next != NULL && pre->next->data < p->data)
			pre = pre->next;
		p->next = pre->next;
		pre->next = p;
		p = r;
	}
}
举报

相关推荐

0 条评论