题目描述

逆置单链表_i++

分析:

这题不难,我看到这题首先就是想到构造一个新的头结点,然后利用头插法将原链表的结点一个一个转移过去,代码如下:

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;
}

提交结果:

逆置单链表_sql_02


可想而知,这种算法利用了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;
}

提交结果:

逆置单链表_#include_03

参考:​​题解出处​​​ 就地逆置图解:​​动态图​

顺序表操作

​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;
// }
//
//}
}