链表的进一步学习
链表的进一步学习
阮阮在上周的学习中学会了链表的基本使用方法,但是好奇心很重的它还是忍不住探索链表的一些用法,于是它向它右边的大神鑫鑫请教,
于是热情的鑫鑫就认真的教了它后面的内容。
学习内容:
一,反转链表(递归,迭代)
二,打印链表(递归)
三,双向链表
一,反转链表:
这个图就是反转链表前后的对比
后面上代码:
这里就是主函数中的应用:
int main() { head = NULL; Insert('r', 1); Insert('w', 2); Insert('t', 3); Insert('n', 4); Insert('b', 5); int n; /*scanf_s("%d", &n); Delete(n);*/ Print(); head = reverse(head);//还有就是发现了没有这个为什么要传会一个头地址呢?? Print();//print函数在打印的时候是根据头地址进行遍历和打印链表的。 return 0; }
struct Node* reverse(struct Node* head) { struct Node* current,*prev,*next; current = head; prev = NULL;//记住创建结点一定要进行初始化, while (current != NULL) { next = current->next;//这个地方之所以要用next是因为如果直接把current转给前一个,它的下一个结点就会失去 current->next = prev; prev = current;//把之前的那个current变成prev current = next;//next就变成了current } //最后current变成NULL,next也变成NULL,原来的head就变成了prev,也就是最后一个结点变成了头。 head = prev; return head; }
最后的反转之后的结果是
成功的反转了链表,反转链表的本质就是把原来链表的结点给断开,然后把这个结点的地址指向上一个节点,但是我这里遇到了一个问题,我直接把结点指向上一个位置后,这个位置下一个地方的地址就丢失了
所以我这里又用一个临时结点来储存下一个结点的地址,然后再将当前结点的位置指向上一个结点,然后就把current的值赋给prev,把next的值赋给current,这样就可以有遍历的效果。然后在最后,current和next'的值全是NULL,将prev的值赋给head,这样head就变成了之前链表的尾部。也就是下面这个图。
二,用递归的方式打印链表(反转):
这里就是用前一段时间学习的递归来理解:
void reverseprint(struct Node* p) {//这个是使用递归进行反转打印 if (p == NULL) { return; } reverseprint(p->next); printf("%d", p->data); }
就是在递归树中,reverseprint不断进行递归,知道p = NULL的时候开始打印,从尾向头开始打印,这里难度不大,但是要记住,一定要有递归的退出条件。
三,双向链表;
这张图就是双向链表的大体结构
就是在data域之前多了一个prev域来指向上一个位子。
下面来讲创建双向链表:
struct Node* getnewnode(int x) { struct Node* newnode = (struct Node*)malloc(sizeof(struct Node)); newnode->data = x; newnode->next = NULL; newnode->prev = NULL; return newnode;//返回newnode的初值 } void Inverathead(int x) { struct Node* newnode = getnewnode(x); if (head == NULL) { head = newnode; } head->prev = newnode; newnode->next = head; head = newnode; } void Reverseprint() { struct Node* temp = head; if (temp == NULL) { return; } while (temp != NULL) { temp = temp->next; } printf("Reverse:"); while (temp != NULL) { printf("%d", temp->data); temp = temp->prev; } printf("\n"); }
上面这一段代码三个函数做了三件事,首先创建了一个双向链表,第一个函数就是开辟双向链表所需的内存空间,当然在这之前还要写上相关的双向链表的struct相比于普通链表而言,双向链表就是多了一个指向前一个结点的指针。第二个函数就是创建的过程了,为了便于理解过程如下:
就是一个把你的prev连到我身上,再把我的next连在你身上,就像事两个人左手牵右手,右手牵左手一个道理。最后这个函数就用到了双向链表的特点进行反向打印,其实说白了,就是正向遍历,在temp到最后的时候再来一个方向打印呗,其实蛮简单的。