链表原地翻转
程序内部:在程序中能够看到的部分,链表中指第一个节点的地址(head指针记录整个链表的地址)
内存内部:在程序中不能看到的部分,链表中指的每一个节点(体现在物理内存中)
1.链表操作
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct Node{
int data;
struct Node *next;
}Node;
typedef struct LinkList{
Node head;//head为虚拟头结点
int length;
}LinkList;
//1.初始化结点
Node *initNode(int val){
Node *node = (Node *)malloc(sizeof(Node));
node->data = val;
node->next = NULL;
return node;
}
//2.初始化链表
LinkList *initList(){
LinkList *llst = (LinkList *)malloc(sizeof(LinkList));
llst->head.next = NULL;
llst->length = 0;
return llst;
}
//3.结点的销毁
void DestroyNode(Node *node){
if(node == NULL) return;
free(node);
return;
}
//4.链表的销毁
void DestroyList(LinkList *llst){
if(llst == NULL) return;
Node *p = llst->head.next;
Node *temp;
while (p != NULL) {
temp = p->next;
DestroyNode(p);
p = temp;
}
free(llst);
return;
}
//5.链表插入
int ListInsert(LinkList *llst, int ind, int val){
if(llst == NULL) return 0;
if(ind < 0 || ind > llst->length) return 0;
Node *p = &(llst->head);//指针p记录虚拟头结点地址
//(1)初始化一个node结点存入val数据
Node *node = initNode(val);
//(2)找到插入位置的前一个位置
while(ind--) p = p->next;
//(3)重新建立索引关系,进行结点插入
node->next = p->next;
p->next = node;
llst->length += 1;
return 1;
}
//6.链表元素的删除操作
int ListDelete(LinkList *llst, int ind) {
if(llst == NULL) return 0;
if(ind < 0 || ind >= llst->length) return 0;
//(1)初始化一个node结点存入val数据
Node *p = &(llst->head);
Node *temp;
//(2)找到插入位置的前一个位置
while(ind--) p = p->next;
//(3)temp记录待删除结点位置,进行删除操作
temp = p->next;
p->next = p->next->next;
DestroyNode(temp);
llst->length -= 1;
return 1;
}
//7.print链表
void print(LinkList *llst) {
if(llst == NULL) return;
printf("LinkList(%d) : ", llst->length);
//遍历LinkList元素
for(Node *p = llst->head.next; p != NULL; p = p->next) {
printf("%d->", p->data);
}
printf("NULL\n");
return;
}
int main(){
srand(time(0));
LinkList *llst = initList();
#define MAX_OP 20
for(int i = 0; i < MAX_OP; ++i){
int val = rand() % 100;
int ind = rand() % (llst->length + 3) - 1;//操作位置随机在范围[-1, sqlst-length + 1]中
int op = rand() % 4;
switch (op) {
case 0:
case 1:
case 2: {
printf("insert %d at %d to List = %d\n", val, ind, ListInsert(llst, ind, val));
} break;
case 3: {
printf("erase a item at %d from List = %d\n", ind, ListDelete(llst, ind));
} break;
}
print(llst);
}
#undef MAX_OP
DestroyList(llst);
return 0;
}
注意:对程序内部和内存内部的理解,决定了链表数据结构的定义方式
2.链表原地翻转
思路1:
- 新创建一个链表
- 遍历已知的链表,将元素不断的插入到新创建的链表中(使用头插法)
思路2:
原地翻转链表,不需要开辟新的空间O(1),注意内存泄漏问题
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define COLOR(a,b) "\033[" #b "m" a "\033[0m"
#define GREEN(a) COLOR(a, 34)
typedef struct Node{
int data;
struct Node *next;
}Node;
typedef struct LinkList{
Node head;//head为虚拟头结点
int length;
}LinkList;
//1.初始化结点
Node *initNode(int val){
Node *node = (Node *)malloc(sizeof(Node));
node->data = val;
node->next = NULL;
return node;
}
//2.初始化链表
LinkList *initList(){
LinkList *llst = (LinkList *)malloc(sizeof(LinkList));
llst->head.next = NULL;
llst->length = 0;
return llst;
}
//3.结点的销毁
void DestroyNode(Node *node){
if(node == NULL) return;
free(node);
return;
}
//4.链表的销毁
void DestroyList(LinkList *llst){
if(llst == NULL) return;
Node *p = llst->head.next;
Node *temp;
while (p != NULL) {
temp = p->next;
DestroyNode(p);
p = temp;
}
free(llst);
return;
}
//5.链表插入
int ListInsert(LinkList *llst, int ind, int val){
if(llst == NULL) return 0;
if(ind < 0 || ind > llst->length) return 0;
Node *p = &(llst->head);//指针p记录虚拟头结点地址
//(1)初始化一个node结点存入val数据
Node *node = initNode(val);
//(2)找到插入位置的前一个位置
while(ind--) p = p->next;
//(3)重新建立索引关系,进行结点插入
node->next = p->next;
p->next = node;
llst->length += 1;
return 1;
}
//6.链表元素的删除操作
int ListDelete(LinkList *llst, int ind) {
if(llst == NULL) return 0;
if(ind < 0 || ind >= llst->length) return 0;
//(1)初始化一个node结点存入val数据
Node *p = &(llst->head);
Node *temp;
//(2)找到插入位置的前一个位置
while(ind--) p = p->next;
//(3)temp记录待删除结点位置,进行删除操作
temp = p->next;
p->next = p->next->next;
DestroyNode(temp);
llst->length -= 1;
return 1;
}
//7.链表原地翻转
void ListReverse(LinkList *llst){
if(llst == NULL) return;
Node *p = llst->head.next;
Node *temp;
llst->head.next = NULL;
while(p != NULL){
temp = p->next;
p->next = llst->head.next;
llst->head.next = p;
p = temp;
}
return;
}
//7.print链表
void print(LinkList *llst) {
if(llst == NULL) return;
printf("LinkList(%d) : ", llst->length);
//遍历LinkList元素
for(Node *p = llst->head.next; p != NULL; p = p->next) {
printf("%d->", p->data);
}
printf("NULL\n");
return;
}
int main(){
srand(time(0));
LinkList *llst = initList();
#define MAX_OP 20
for(int i = 0; i < MAX_OP; ++i){
int val = rand() % 100;
int ind = rand() % (llst->length + 3) - 1;//操作位置随机在范围[-1, sqlst-length + 1]中
int op = rand() % 4;
switch (op) {
case 0: {
printf(GREEN("reverse the list!\n"));
ListReverse(llst);
} break;
case 1:
case 2: {
printf("insert %d at %d to List = %d\n", val, ind, ListInsert(llst, ind, val));
} break;
case 3: {
printf("erase a item at %d from List = %d\n", ind, ListDelete(llst, ind));
} break;
}
print(llst);
}
#undef MAX_OP
DestroyList(llst);
return 0;
}
ListReverse操作:
//7.链表原地翻转
void ListReverse(LinkList *llst){
if(llst == null) return;
Node *p = head->next;
Node *temp;
head->next = NULL;
while(p != NULL){
temp = p->next;
p->next = head->next;
head->next = p;
p = temp;
}
return;
}