单向链表和双向链表的反转
第一次写博客,水平和经验都不足,如有错误,还请批评指正,谢谢!
单向链表
单向链表分为有头结点和无头结点,有头结点可以简化一些操作,但是无头结点的链表容易理解一些,下面讨论的都是无头节点的单向链表。
单向链表的反转可以理解为对链表中的每一个节点进行头插入即从头部插入,这样就把链表分成了两部分,前面已经反转的部分和后面待反转的部分,所以需要额外的两个节点直接来指向这两部分,具体操作如下图所示:
开始时,temp
和prev
指针均指向头结点,然后temp=temp->next
使得temp
指向想一个节点,即保存后一部分链表的首地址,然后使得temp->next=NULL
单链表的最后一个节点的next
指向NULL
,重复如下操作
start = temp;
temp = temp->next;
start->next = prev;
prev = start;
如下图所示:
这样最后temp
为NULL
,start
刚好为最后一个节点的地址,也即反转后的链表首地址。具体代码如下:
#include <stdio.h>
#include <stdlib.h>
struct slinklist
{
int data;
struct slinklist *next;
};
typedef struct slinklist node;
node *start = NULL;
node *getnode() //get a node
{
node *newnode;
newnode = malloc(sizeof(node));
printf("enter data: ");
scanf("%d",&newnode->data);
newnode->next = NULL;
return newnode;
}
void createlist(int n) // create a single linked list for n nodes
{
int i;
node *newnode;
node *temp;
for(i=0;i<n;i++)
{
newnode = getnode();
if(start == NULL)
start = newnode;
else
{
temp = start;
while(temp->next!=NULL)
temp = temp->next;
temp->next = newnode;
}
}
}
void traverse()
{
node *temp;
temp = start;
printf("the contents of list (left to right): \n");
if(start == NULL)
printf("empty list.\n");
else
{
while(temp!=NULL)
{
printf("%d ->",temp->data);
temp = temp->next;
}
}
printf("X");
}
void flip() //链表反转
{
node *temp, *prev;
temp = prev = start;
temp = temp->next;
prev->next = NULL;
while(temp!=NULL)
{
start = temp;
temp = temp->next;
start->next = prev;
prev = start;
}
}
int main(void)
{
int number;
printf("enter the number of nodes of signle-linked list: ");
scanf("%d",&number);
createlist(number);
printf("\n----------------traverse------------------\n");
traverse();
printf("\n------------------flip---------------------\n");
flip();
traverse();
}
利用gcc编译运行
gcc slinkedlist.c -o slinklist -Wall
运行结果如下:
enter the number of nodes of signle-linked list: 5
enter data: 1
enter data: 2
enter data: 3
enter data: 4
enter data: 5
----------------traverse------------------
the contents of list (left to right):
1 ->2 ->3 ->4 ->5 ->X
------------------flip---------------------
the contents of list (left to right):
5 ->4 ->3 ->2 ->1 ->X
双向链表
双向链表与单链表类似,可以把单向链表的操作看成是双向链表的右侧链接的操作,在此基础上再把左侧链接的操作加上即可实现双向链表的反转,具体的操作如下图所示:
start = temp;
temp = temp->right;
start->right = prev;
prev->left = start;
prev = start;
另外双向链表的首节点的left
和最后一个节点的right
为NULL,所以最后操作完成后,还需要将start->left=NULL
,新首节点的left
设为NULL
,具体代码如下:
#include <stdio.h>
#include <stdlib.h>
struct dlinklist
{
struct dlinklist *left;
int data;
struct dlinklist *right;
};
typedef struct dlinklist node;
node *start = NULL;
node *getnode() // get a node
{
node *newnode;
newnode = malloc(sizeof(node));
printf("enter data: ");
scanf("%d",&newnode->data);
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
void createlist(int n) // create a single linked list for n nodes
{
int i;
node *newnode;
node *temp;
for(i=0;i<n;i++)
{
newnode = getnode();
if(start == NULL)
start = newnode;
else
{
temp = start;
while(temp->right!=NULL)
temp = temp->right;
temp->right= newnode;
newnode->left = temp;
}
}
}
void traverse()
{
node *temp;
temp = start;
printf("\nthe contents of list (left to right): \n");
if(start == NULL)
printf("empty list.\n");
else
{
while(temp!=NULL)
{
printf("%d ->",temp->data);
temp = temp->right;
}
}
printf("X");
}
void rev_traverse()
{
node *temp;
printf("\nthe contents of list (right to left): \n");
if(start== NULL)
return;
else
{
temp = start;
while(temp->right!=NULL)
temp = temp->right;
while(temp!=NULL)
{
printf("%d ->",temp->data);
temp = temp->left;
}
}
}
void fliponce()
{
node *temp,*prev;
temp = prev = start;
temp = temp->right;
prev->right = NULL; //双向链表第一个节点的left和最后一个节点的right为NULL
while(temp!=NULL)
{
start = temp;
temp = temp->right;
start->right = prev;
prev->left = start;
prev = start;
}
start->left = NULL; //双向链表第一个节点的left和最后一个节点的right为NULL
//而双向循环链表把第一个节点的left和最后一个节点的right给连上
}
int main(void)
{
int number;
printf("enter the number of nodes of double-linked list: ");
scanf("%d",&number);
createlist(number);
printf("\n----------------traverse------------------\n");
traverse();
printf("\n----------------rev_traverse------------------\n");
rev_traverse();
printf("\n------------------fliponce-----------------------\n");
fliponce();
traverse();
rev_traverse();
}
编译运行
gcc dlinkedlist.c -o dlinkedlist -Wall
结果如下:
enter the number of nodes of double-linked list: 5
enter data: 1
enter data: 2
enter data: 3
enter data: 4
enter data: 5
----------------traverse------------------
the contents of list (left to right):
1 ->2 ->3 ->4 ->5 ->X
----------------rev_traverse------------------
the contents of list (right to left):
5 ->4 ->3 ->2 ->1 ->
------------------fliponce-----------------------
the contents of list (left to right):
5 ->4 ->3 ->2 ->1 ->X
the contents of list (right to left):
1 ->2 ->3 ->4 ->5 ->