打怪升级第一天:
大家好,今天我们来了解一下数组和单链表的原地逆置问题。
那么首先:何为原地逆置?
就是在不创建额外的数组或链表,在空间复杂度为O(1)的情况下完成逆置,
下面我们实际操作起来。
示例:
void Reverse(int arr[], int n)
{
int left = 0;//可以使用指针,也可以使用下标
int right = n - 1;
while (left < right)//左右下标重合表明交换完毕
{
int con = arr[left];
arr[left] = arr[right];
arr[right] = con;
left++;
right--;
}
}
int main()
{
int arr[100] = { 0 };
printf("请输入数组元素的个数:");
int n = 0;
scanf("%d", &n);
int i = 0;
for (i = 0; i < n; i++)
scanf("%d", arr + i);
Reverse(arr, n);
printf("逆置结果:");
for (i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
图解 + 运行实例:
为了方便阅读,前面只给出主要代码,整体代码会放到文章最后。
示例:
//模拟顺序表双指针
void Reverse(LN* left, int num)
{
int con = 0;
while (con < num / 2)
{
LN* right = left;
int i = 1;
while (i < num - 2 * con)//寻找需要交换的右边的节点
{
right = right->next;
i++;
}
int tmp = left->data;
left->data = right->data;
right->data = tmp;
left = left->next;
con++;
}
}
图解:
示例:
//打断链表,以头插法进行插入
void Reverse(LN* ph)
{
LN* paim;//需要插入的节点
LN* ptr;//下一个节点
paim = ph->next;
ph->next = NULL;//先将头结点置空,之后在头结点之后进行插入
while (paim)
{
ptr = paim->next;
paim->next = ph->next;
ph->next = paim;
paim = ptr;
}
}
图解:
示例:
//递归实现,由于无法从后一个节点找到前一个节点,所以从倒数第二个节点开始操作
LN* Reverse(LN* ph)
{
if (ph == NULL || ph->next == NULL)//终止递归的条件
{
return ph;//最后一个节点不在这一步进行操作
}
LN* pend = Reverse(ph->next);
ph->next->next = ph;
ph->next = NULL;
return pend;//返回最后一个节点的指针
}
图解:
#define MALLOC(ty,num) (ty*)malloc(sizeof(ty)*(num))
//原地逆序:单链表
typedef struct LinkedNode
{
int data;
struct LinkedNode* next;
}LN;
void Init(LN* ph, int num)
{
for (int i = 0; i < num; i++)
{
LN* ptr = MALLOC(LN, 1);
if (ptr == NULL)
{
perror("Init::MALLOC");
exit(1);
}
printf("请输入第%d个节点值:", i + 1);
scanf("%d", &ptr->data);
ptr->next = NULL;
ph->next = ptr;
ph = ptr;
}
}
void Print(LN* ph)
{
LN* p = ph->next;
printf("结果:");
while (p != NULL)
{
printf("%d ", p->data);
ph = p;
p = p->next;
free(ph);
}
}
//递归实现,由于无法从后一个节点找到前一个节点,所以从倒数第二个节点开始操作
LN* Reverse(LN* ph)
{
if (ph == NULL || ph->next == NULL)//终止递归的条件
{
return ph;
}
LN* pend = Reverse(ph->next);
ph->next->next = ph;
ph->next = NULL;
return pend;//返回最后一个节点的指针
}
打断链表,以头插法一个一个得插入
//void Reverse(LN* ph)
//{
// LN* paim;//即将插入的节点
// LN* ptr;//下一个节点
// paim = ph->next;
// ph->next = NULL;
// while (paim)
// {
// ptr = paim->next;
// paim->next = ph->next;
// ph->next = paim;
// paim = ptr;
// }
//}
在变化过程中链表一直未打断,,但是过于复杂
//void Reverse(LN* ph)
//{
//
// LN* ptr = ph->next;
// while (ptr->next)
// {
// LN* p1 = ph->next;
// LN* p2 = ptr->next;
// ph->next = ptr->next;
// ptr->next = ptr->next->next;
// p2->next = p1;
// }
//}
模拟顺序表双指针
//void Reverse(LN* left, int num)
//{
// int con = 0;
// while (con < num / 2)
// {
// LN* right = left;
// int i = 1;
// while (i < num - 2 * con)//寻找需要交换的右边的节点
// {
// right = right->next;
// i++;
// }
// int tmp = left->data;
// left->data = right->data;
// right->data = tmp;
// left = left->next;
// con++;
// }
//}
//带头单链表:原地逆置
int main()
{
LN* head = MALLOC(LN, 1);//头结点
if (head == NULL)
{
perror("main::MALLOC");
exit(1);
}
head->next = NULL;
printf("请输入与节点个数:");
int num = 0;
scanf("%d", &num);
Init(head, num);
//Reverse(head->next, num);
//Reverse(head);
head->next = Reverse(head->next);//从头结点后一个节点开始逆置
Print(head);
free(head);
return 0;
}
运行实例:
以上就是今天讲解的线性表逆置的全部内容,如果有什么疑问或者建议都可以在评论区留言,感谢大家对的支持。