浅谈单链表和顺序表

*单链表 ,顾名思义是一种链式结构,同时呢也是一条单链。

*由于“单恋”呢,我们的结构是简单的,写起来没有那么复杂,但是同时呢,由于单链的物理原因,也有很多短板,那么  下面就是我对单链表的一些理解和认识。

*我们都知道单链的最小单元是一个个的结点,然后再将这些结点串起来变成一条链,在这个节点数据块放入数据,然后让其指针块来指向下一个结点,这样就是他们连起来的,就是我的单链表了,下面我们来看一下单链表的结构。

//代码如下
typedef int Datatype;
typedef struct Node
{
	Datatype _data;
	struct Node*next;
};

Node * BuyNode(Datatype value)
{
	Node *newNode = (Node*)malloc(sizeof(Node));
	assert(newNode);
	newNode->_data = value;
	newNode->next = NULL;
	return newNode;
}


void Pushback(Node** pphead, Datatype value)
{
	if (*pphead == NULL)
	{
		*pphead = BuyNode(value);
	}
	else
	{
		Node* cur = *pphead;

		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = BuyNode(value);
	}
}

下面是链表的基本操作

//尾删
void Popback(Node **phead)
{
	assert(*phead);
	if ((*phead)->next == NULL)
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		Node *cur = *phead;
		Node *prve = *phead;
		while (cur->next)
		{
			prve = cur;
			cur = cur->next;
		}
		prve->next = NULL;
		free(cur);
		cur = NULL;
	}
}
//打印链表
void ShowList(Node *phead)
{
	assert(phead);
	while (phead)
	{
		cout << phead->_data << " " << "";
		phead = phead->next;
	}
	
	cout << endl;
}

//头插
void Pushfront(Node **pphead, Datatype value)
{
	if (*pphead == NULL)
	{
		(*pphead) = BuyNode(value);
	}
	else
	{
		Node *newNode = BuyNode(value);
		newNode->next = (*pphead);
		*pphead = newNode;
	}

}
//头删
void Popfront(Node **pphead)
{
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		Node *tmp = *pphead;
		*pphead = (*pphead)->next;
		free(tmp);
	}
}
//pos位置插入
void PushInsert(Node **pphead, Node *pos, Datatype value)
{
	assert(*pphead);
	Node *prve = *pphead;
	if (prve->next == NULL)
	{
		Pushfront(pphead,value);
	}
	else
	{
		while (prve->next != pos)
		{
			prve = prve->next;
		}
		Node *newNode = BuyNode(value);
		newNode->next = pos;
		prve->next = newNode;

	}

}
//删除pos位置
void Erase(Node** ppList, Node* pos)
{
	assert(*ppList);
	if ((*ppList)->next == NULL)
	{
		free(*ppList);
		(*ppList) = NULL;
	}
	else
	{
		Node *prve = *ppList;
		while (prve->next != pos)
		{
			prve = prve->next;
		}
		prve->next = pos->next;
		free(pos);
		pos = NULL;
	}

}
//查找
Node* Find(Node *phead,Datatype value)
{
	Node *cur = phead;
	while (cur)
	{
		if (cur->_data == value)
		{
			return cur;
		}
		cur = cur->next;
	}
}
//删除无头链表

//下面面无头的删除和插入都是在非头尾结点
void EraseNoHead(Node*pos)
{
	assert(pos);
	Node* next = pos->next;
	pos->_data = next->_data;
	pos->next = next->next;
	free(next);
}


void InsertNonHead(Node *pos,Datatype value)
{
	assert(pos);
	
	Node* next = pos->next;
	Node* newNode = BuyNode(value);
	newNode->_data = pos->_data;
	pos->_data = value;
	pos->next = newNode;
	newNode->next = next;
}

//约瑟夫环问题


//代码如下

Node *JosepHus(Node *head,size_t k)
{
	assert(head);
	Node *man = head;
	while (man->next != man)
	{
		size_t temp = k;
		while (--temp)
		{
			man = man->next;
		}
		EraseNoHead(man);

	}
	return man;
}
//逆置链表
思路:用三个指针分别指头结点前一个NULL,n1指向头结点,n2指向头结点下一个结点,每次让n1的next指向n0,n0被赋值为n1,n2被赋值成它的下一个结点

代码如下:
void  ReveList(Node** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}

	Node *n0 = NULL;
	Node *n1 = *pphead;
	Node *n2 = (*pphead)->next;
	while (n1)
	{
		n1->next = n0;
		n0 = n1;
		n1 = n2;
		if (n2)
		{
			n2 = n2->next;
		}
	}
	*pphead = n0;
}
//求一个单链表的中间结点倒数K结点问题
思路:这里是一个快慢指针的问题,再求中间结点时,快指针每次走两步,慢指针每次走一步,这样当快指针走到了链表的尾部时,慢指针走的了快指针的一半,即要求的中间结点。再求倒数第k个结点问题时,一样的先让快指针先走k-1步,然后快慢指针一起向后每次都只走一步,这样快慢指针中间差了k-1步,等快指针到了尾时,慢指针就是倒数第k个结点,图示如下:

代码如下:
Node * GetMidNode(Node *phead)
{
	if (phead == NULL || phead->next == NULL)
	{
		cout << "no exit" << "";
		return NULL;
	}

	Node *fast = phead;
	Node *slow = phead;
	while (fast &&fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}
//单链表带环问题
思路:还是一个快慢指针的问题,因为快指针每次走两步,慢指针每次走一部,所以当慢指针进入环里时,这时便开始快指针追慢指针,因为每次都能缩小一步,所以一定能追上慢指针,即相遇。求解环长度问题就是记录相遇的结点meet,然后接着向后走,没走一次计数器++,当下次在遇见meet时,此时计数器的值就是环的长度。环的入口问题则是两个指针,一个从头结点开始走,一个从meet结点开始走,当他们相遇的结点就是入口节点entry结点。
//判断带环与否,和求相遇结点meet
//下面是求环入口点:
//相关代码如下:
//看一个结点是否有环返回meet
Node *IsCircle(Node *phead)
{
	Node *fast = phead;
	Node *slow = phead;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;

		if (fast->_data == slow->_data)
		{
			return fast;
		}
	}
	return NULL;
}

//一个单环求entry
Node *GetMeetNode(Node *phead)
{
	Node *meet = IsCircle(phead);
	Node *entry = meet;
	while (entry->_data != phead->_data)
	{
		entry = entry->next;
		phead = phead->next;
	}
	return entry;
}
//两个相遇的单链表求相遇结点
//代码如下
//两个List求meet
Node *GetMeetNodeDouList(Node *list1, Node*list2)
{
	int len1 = 0;
	int len2 = 0;
	int gas = 0;
	Node *cur1 = list1;
	Node *cur2 = list2;

	while (cur1)
	{
		len1++;
		cur1 = cur1->next;
	}
	while (cur2)
	{
		len2++;
		cur2 = cur2->next;
	}
	gas = abs(len1-len2);
	Node *shortList = list1;
	Node *longList = list2;
	if (len1 > len2)
	{
		shortList = list2;
		longList = list1;
	}
	while (gas--)
	{
		longList = longList->next;
	}
	while (shortList->_data != longList->_data)
	{
		shortList = shortList->next;
		longList = longList->next;
	}
	return shortList;
}
//两个单链表相遇(带环的情况)
思路:这样问题和前面讲的问题很类似,这里就不做过多的解释了,在前面的基础上也只增加了一点,这里有两种情况的相遇需要我们注意,如下图:

如有错误,还请见谅,可以和我联系,我会及时改正,毕竟这是一个学习的过程,你的








猜你喜欢

转载自blog.csdn.net/skinwhite/article/details/78067521