题目描述
分析:
这题不难,我看到这题首先就是想到构造一个新的头结点,然后利用头插法将原链表的结点一个一个转移过去,代码如下:
ListNode* reverseList(ListNode* head) {
//转移结点法
if(head == NULL) return head;
ListNode* new_head = (ListNode*)malloc(sizeof(ListNode));
new_head->next = NULL;
ListNode* trans = head;
ListNode* cur = trans->next;
trans->next = NULL;
while(cur != NULL){
trans->next = new_head->next;
new_head->next = trans;
trans = cur;
cur = trans->next;
trans->next = NULL;
}
//当cur为空时,其实最后一个结点与新构造的链表还没有完成插入操作
//下面将最后一个结点插入
trans->next = new_head->next;
new_head->next = trans;
return new_head->next;
}
提交结果:
可想而知,这种算法利用了O(1)的额外空间,还进行了转运操作,效率并不太高,从提交结果也可以看得出来。于是我开始翻看题解,果然有大神写了就地逆置的算法,看完后,我将算法重新写了一遍。
就地逆置代码如下:
ListNode* reverseList(ListNode* head) {
//就地逆置法
if(head == NULL) return head;
ListNode* cur = head;
ListNode* leader = cur->next;
ListNode* pre = NULL;
while(cur != NULL){
cur->next = pre;// 改变next指向
pre = cur;
cur = leader ;
if(leader != NULL) leader = leader ->next;
}
return pre;
}
提交结果:
顺序表操作
seqlist.h
#pragma once
typedef struct {
int* arr; //动态内存地址
int length;
int list_size;
}Dsqlist, *ptr_dsqlist;
void init_seqlist(ptr_dsqlist ptr_s);
void destory(ptr_dsqlist ptr_s);
void clear(ptr_dsqlist ptr_s);
bool is_empty(const ptr_dsqlist ptr_s);
// static对内使用,不对外使用。对外部而言,永远不满。满了就会扩容
static bool is_full(const ptr_dsqlist ptr_s);
bool get_length(const ptr_dsqlist ptr_s, int* length);
bool get_pos_elem(const ptr_dsqlist ptr_s, int pos, int* re_val);
bool get_prior(const ptr_dsqlist ptr_s, int pos, int* re_val);
bool get_next(const ptr_dsqlist ptr_s, int pos, int* re_val);
static void inc_seqlist(ptr_dsqlist ptr_s);
bool insert(ptr_dsqlist ptr_s, int pos, int val);
bool delete_pos(ptr_dsqlist ptr_s, int pos, int* deleted_val);
bool delete_val(ptr_dsqlist ptr_s, int val);
void show(const ptr_dsqlist ptr_s);
// 返回下标或者-1
int search(const ptr_dsqlist ptr_s, int val);
seqlist.cpp
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include "seqlist.h"
#define INITSIZE 100
void init_seqlist(ptr_dsqlist ptr_s) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return;
}
assert(ptr_s->arr != nullptr);
ptr_s->arr = (int*)malloc(sizeof(int)*INITSIZE);
ptr_s->length = 0;
ptr_s->list_size = INITSIZE;
}
void destory(ptr_dsqlist ptr_s) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return;
}
free(ptr_s->arr);
ptr_s->arr = nullptr;// 不置空,为野指针
ptr_s->length = 0;
ptr_s->list_size = 0;
/*free(ptr_s);
ptr_s = nullptr;*/
}
void clear(ptr_dsqlist ptr_s) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return;
}
for (int i = 0; i < ptr_s->length; i++) {
ptr_s->arr[i] = 0;
}
}
bool is_empty(const ptr_dsqlist ptr_s) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
return ptr_s->length == 0;
}
bool get_length(const ptr_dsqlist ptr_s, int* length) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
*length = ptr_s->length;
return true;
}
bool get_pos_elem(const ptr_dsqlist ptr_s, int pos, int* re_val) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
// 判断pos是否合法
if (pos < 0 || pos > ptr_s->length) {
return false;
}
assert(re_val != nullptr);
*re_val = ptr_s->arr[pos];
return true;
}
bool get_prior(const ptr_dsqlist ptr_s, int pos, int* re_val) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
// 判断pos是否合法
if (pos <= 0 || pos > ptr_s->length) {
printf("顺序表长度为:%d\n", ptr_s->length);
printf("%d位置没有前驱!\n", pos);
return false;
}
if (re_val != nullptr) {
*re_val = ptr_s->arr[pos - 1];
}
return true;
}
bool get_next(const ptr_dsqlist ptr_s, int pos, int* re_val) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
// 判断pos是否合法
if (pos < 0 || pos >= ptr_s->length - 1) {
printf("顺序表长度为:%d\n", ptr_s->length);
printf("%d位置没有后继!\n", pos);
return false;
}
if (re_val != nullptr) {
*re_val = ptr_s->arr[pos + 1];
}
return true;
}
bool delete_pos(ptr_dsqlist ptr_s, int pos, int* deleted_val) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
if (deleted_val != nullptr) {
*deleted_val = ptr_s->arr[pos];
}
// 判断删除位置合法
if (pos < 0 || pos > ptr_s->length) {
return false;
}
for (int i = pos; i+1 < ptr_s->length; i++) {
ptr_s->arr[i] = ptr_s->arr[i+1];
}
ptr_s->length--;
return true;
}
bool delete_val(ptr_dsqlist ptr_s, int val) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
for (int i = 0; i < ptr_s->length; i++) {
if (ptr_s->arr[i] == val) {
for (int j = i + 1; j < ptr_s->length; j++) {
ptr_s->arr[j-1] = ptr_s->arr[j];
}
ptr_s->length--;
i--;// 再指向上一个不是val的元素
if (i == ptr_s->length) {
return true;
}
}
}
return true;
}
// 返回索引
int search(const ptr_dsqlist ptr_s, int val) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return -1;
}
for (int i = 0; i < ptr_s->length; i++) {
if (ptr_s->arr[i] == val) {
return i;
}
}
return -1;
}
static void inc_seqlist(ptr_dsqlist ptr_s) {
// 保存原有数据,扩容
ptr_s->arr = (int*)realloc(ptr_s, 2 * ptr_s->list_size * sizeof(int));
assert(ptr_s->arr != nullptr);
ptr_s->list_size *= 2;
}
// static对内使用,不对外使用。对外部而言,永远不满。满了就会扩容
static bool is_full(const ptr_dsqlist ptr_s) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return false;
}
return ptr_s->length == ptr_s->list_size;
}
bool insert(ptr_dsqlist ptr_s, int pos, int val) {
// 插入位置不合法
if (pos < 0 || pos > ptr_s->length) {
return false;
}
// 顺序表满了
if (is_full(ptr_s)) {
inc_seqlist(ptr_s);
}
// 从后往前覆盖
for (int i = ptr_s->length; i >= pos; i--) {
ptr_s->arr[i + 1] = ptr_s->arr[i];
}
ptr_s->arr[pos] = val;
ptr_s->length++;
return true;
}
void show(const ptr_dsqlist ptr_s) {
assert(ptr_s != nullptr);
if (ptr_s == nullptr) {
return ;
}
for (int i = 0; i < ptr_s->length; i++) {
printf("%d ", ptr_s->arr[i]);
}
printf("\n");
}
test.cpp
#include"seqlist.h"
#include<stdio.h>
int main() {
Dsqlist seq_list;
init_seqlist(&seq_list);
for (int i = 0; i < 10; i++) {
insert(&seq_list, i, i+1);
}
show(&seq_list);
insert(&seq_list, 1, 100);
show(&seq_list);
insert(&seq_list, 1, 100);
show(&seq_list);
insert(&seq_list, 4, 100);
show(&seq_list);
delete_val(&seq_list, 100);
show(&seq_list);
int re_val = 0;
int pos = 10;
bool has_next = get_next(&seq_list, pos, &re_val);
if (has_next) {
printf("%d位置的后继为:%d\n", pos, re_val);
}
return 0;
}
单链表操作
list.h
# pragma once
typedef int ElemType;
typedef struct Node {
ElemType data;
struct Node* next;
}Node, *List; // List == Node*
// typedef Node* List;//List == Node*
void init_linklist(Node* ptr_head);
void destory(Node* ptr_head);
void clear(Node* ptr_head);
bool is_empty(const Node* ptr_head);
// static对内使用,不对外使用。对外部而言,永远不满。满了就会扩容
static bool is_full(const Node* ptr_head);
int get_length(const Node* ptr_head);
bool get_pos_elem(const Node* ptr_head, int pos, int* re_val);
bool get_prior(const Node* ptr_head, int pos, int* re_val);
bool get_next(const Node* ptr_head, int pos, int* re_val);
static void inc_seqlist(Node* ptr_head);
bool insert_pos(Node* ptr_head, int pos, int val);
bool insert_head(Node* ptr_head, int val);
bool insert_tail(Node* ptr_head, int val);
bool delete_pos(Node* ptr_head, int pos, int* deleted_val);
bool delete_val(Node* ptr_head, int val);
void show(const Node* ptr_head);
Node* search(const Node* ptr_head, int val);
list.cpp
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"list.h"
void init_linklist(Node* ptr_head) {
assert(ptr_head != NULL);
if (ptr_head == NULL) {
return;
}
ptr_head->next = NULL;
}
// 头结点不删除,头结点非malloc
void destory(Node* ptr_head) {
assert(ptr_head != NULL);
Node* cur = ptr_head->next;
ptr_head->next = NULL;
while (cur != NULL) {
Node* tmp = cur;
cur = cur->next;
tmp->next = NULL;
printf("释放:%d\n", tmp->data);
free(tmp);
}
}
void clear(Node* ptr_head) {
destory(ptr_head);
}
bool is_empty(const Node* ptr_head) {
return ptr_head->next == NULL;
}
// static对内使用,不对外使用。对外部而言,永远不满。满了就会扩容
static bool is_full(const Node* ptr_head);
int get_length(const Node* ptr_head) {
int cnt = 0;
for (Node* tmp = ptr_head->next; tmp != NULL; tmp = tmp->next) {
cnt++;
}
return cnt;
}
bool get_pos_elem(const Node* ptr_head, int pos, int* re_val) {
assert(ptr_head != NULL);
if (pos<0 || pos >= get_length(ptr_head)) {
return false;
}
Node* tmp = ptr_head->next;
for (int i = 0; i < pos; i++) {
tmp = tmp->next;
}
if (re_val != NULL) {
*re_val = tmp->data;
}
return true;
}
bool get_prior(const Node* ptr_head, int pos, int* re_val) {
assert(ptr_head != NULL);
if (pos <= 0 || pos >= get_length(ptr_head)) {
return false;
}
Node* tmp = ptr_head->next;
for (int i = 0; i < pos-1; i++) {
tmp = tmp->next;
}
if (re_val != NULL) {
*re_val = tmp->data;
}
return true;
}
bool get_next(const Node* ptr_head, int pos, int* re_val) {
assert(ptr_head != NULL);
if (pos < 0 || pos >= get_length(ptr_head)-1) {
return false;
}
Node* tmp = ptr_head->next;
for (int i = 0; i < pos + 1; i++) {
tmp = tmp->next;
}
if (re_val != NULL) {
*re_val = tmp->data;
}
return true;
}
static void inc_seqlist(Node* ptr_head);
bool insert_pos(Node* ptr_head, int pos, int val) {
assert(ptr_head != NULL);
if (pos < 0 || pos > get_length(ptr_head)) {
return false;
}
Node* tmp = ptr_head->next;
for (int i = 0; i < pos-1; i++) {
tmp = tmp->next;
}
Node* new_node = (Node*)malloc(sizeof(Node));
new_node->data = val;
new_node->next = tmp->next;
tmp->next = new_node;
return true;
}
bool insert_head(Node* ptr_head, int val) {
// 节点需要从堆区申请
Node* new_node = (Node*)malloc(sizeof(Node));
assert(new_node != NULL);
if (new_node == NULL) {
return false;
}
new_node->data = val;
new_node->next = ptr_head->next;
ptr_head->next = new_node;
/*
Node new_node; // 这里不能使用局部变量,否则退出函数后,节点会被回收
node.data = val;
new_node.next = ptr_head->head;
ptr_head->next = &new_node;
*/
return true;
}
bool insert_tail(Node* ptr_head, int val) {
Node* new_node = (Node*)malloc(sizeof(Node));
assert(new_node != NULL);
if (new_node == NULL) {
return false;
}
new_node->data = val;
// 找尾巴
Node* tail = ptr_head;
while (tail->next != NULL) {
tail = tail->next;
}
new_node->next = tail->next;
tail->next = new_node;
return true;
}
Node* search(const Node* ptr_head, int val) {
Node* tmp = (Node*)ptr_head->next;
while (tmp != NULL) {
if (tmp->data == val) {
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
//前驱信息: for (Node* cur = ptr_head; cur->next != NULL; cur = cur->next)
//遍历数据节点: for (Node* cur = ptr_head->next; cur != NULL; cur = cur->next)
bool delete_pos(Node* ptr_head, int pos, int* deleted_val) {
assert(ptr_head != NULL);
if (pos < 0 || pos >= get_length(ptr_head)) {
return false;
}
Node* cur = ptr_head->next;
for (int i = 0; i < pos - 1; i++) {
cur = cur->next;
}
Node* del = cur->next;
cur->next = del->next;
del->next = NULL;
*deleted_val = del->data;
free(del);
return true;
}
bool delete_val(Node* ptr_head, int val);
void show(const Node* ptr_head) {
// 带有头节点的遍历方法
const Node* tmp = ptr_head->next;
while (tmp != NULL) {
printf("%d ", tmp->data);
tmp = tmp->next;
}
printf("\n");
}
void reverse(Node* ptr_head) {
if (ptr_head == NULL || ptr_head->next == NULL || ptr_head->next->next == NULL) {
return;
}
Node* cur = ptr_head->next; // 第一个数据结点
ptr_head->next = NULL;
Node* leader;
while (cur != NULL) {
leader = cur->next;
cur->next = ptr_head->next;
ptr_head->next = cur;
cur = leader;
}
//Node* cur = ptr_head->next; // 第一个数据结点
//ptr_head->next = NULL;
//Node* leader = cur->next;
//while (cur != NULL) {
// cur->next = ptr_head->next;
// ptr_head->next = cur;
// cur = leader;
// if (leader != NULL) {
// leader = leader->next;
// }
//
//}
}