1、顺序表存在的问题
顺序表存在一些问题:
- (1)中间、头部的插入删除,时间复杂度为O(N)
- (2)增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
- (3)增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
- 解决办法:单链表
2、单链表
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
3、单链表实现
(1)Slist.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
//打印
void SLTPrint(SLTNode* phead);
//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);
//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x);
//头删
void SLPopFront(SLTNode** pphead);
//尾删
void SLPopBack(SLTNode** pphead);
//单链表查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x);
//在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos);
//删除pos位置后面的值
void SLEraseAfter(SLTNode* pos);
// 单链表的销毁
void SListDestroy(SLTNode** pphead);
(2)Slist.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Slist.h"
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNode* BuyLTNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead); //链表为空,pphead也不为空,因为他是头指针plist的地址
//assert(*pphead); //不能断言,链表为空,也需要能插入
SLTNode* newnode = BuyLTNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuyLTNode(x);
//空链表
//非空
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SLPopFront(SLTNode** pphead)
{
assert(pphead); //链表为空,pphead也不为空,因为他是头指针plist的地址
//链表为空
assert(*pphead); //链表为空,不能头删(当然你还可以用温柔的检查)
一个节点
多个节点
//if ((*pphead)->next == NULL)
//{
// free(*pphead);
// *pphead = NULL;
//}
//else
//{
// SLTNode* del = *pphead;
// //*pphead = del->next;
// *pphead = (*pphead)->next;
// free(del);
//}
//一个节点和多个节点的情况合并
SLTNode* del = *pphead;
*pphead = del->next;
free(del);
}
void SLPopBack(SLTNode** pphead)
{
assert(pphead); //链表为空,pphead也不为空,因为他是头指针plist的地址
//链表为空【暴力检查】
assert(*pphead); // 链表为空,不能尾删(当然你还可以用温柔的检查)
//温柔检查
/*if (*pphead == NULL)
{
return;
}*/
//一个节点
//多个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* tail = *pphead;
//找倒数第二个节点
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next); //释放尾节点
tail->next = NULL;
}
}
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
printf("查找%d成功\n", x);
return cur;
}
else
{
cur = cur->next;
}
}
printf("查找%d失败\n", x);
return NULL;
}
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
if (*pphead == NULL)
{
SLPushFront(pphead, x);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLTNode* newnode = BuyLTNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuyLTNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SLErase(SLTNode** pphead, SLTNode* pos)
{
assert(pos);
assert(pphead);
if (pos == *pphead)
{
SLPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}
void SLEraseAfter(SLTNode* pos)
{
assert(pos);
assert(pos->next);
SLTNode* Next = pos->next;
pos->next = Next->next;
free(Next);
}
void SListDestroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* Next = cur->next; //先保存一下下一个节点的地址
free(cur);
cur = Next;
}
*pphead = NULL;
}
(3)Test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Slist.h"
void test1()
{
SLTNode* plist = NULL;
SLPushFront(&plist, 5);
SLPushFront(&plist, 4);
SLPushFront(&plist, 3);
SLPushFront(&plist, 2);
SLPushFront(&plist, 1);
SLPushBack(&plist, 6);
SLPushBack(&plist, 7);
SLPushBack(&plist, 8);
SLPushBack(&plist, 9);
SLPushBack(&plist, 10);
SLPopBack(&plist);
SLPopBack(&plist);
SLPopFront(&plist);
SLPopFront(&plist);
SLTPrint(plist);
SListDestroy(&plist);
}
void test2()
{
SLTNode* plist = NULL;
SLPushFront(&plist, 5);
SLPushFront(&plist, 4);
SLPushFront(&plist, 3);
SLPushFront(&plist, 2);
SLPushFront(&plist, 1);
SLPushBack(&plist, 6);
SLPushBack(&plist, 7);
SLPushBack(&plist, 8);
SLPushBack(&plist, 9);
SLPushBack(&plist, 10);
//查找节点并修改节点
SLTNode* pos = SLFind(plist, 5);
if (pos)
{
pos->data = 50;
}
pos = SLFind(plist, 11);
if (pos)
{
pos->data = 50;
}
SLTPrint(plist);
SListDestroy(&plist);
}
void test3()
{
SLTNode* plist = NULL;
SLPushFront(&plist, 5);
SLPushFront(&plist, 4);
SLPushFront(&plist, 3);
SLPushFront(&plist, 2);
SLPushFront(&plist, 1);
SLPushBack(&plist, 6);
SLPushBack(&plist, 7);
SLPushBack(&plist, 8);
SLPushBack(&plist, 9);
SLPushBack(&plist, 10);
SLTNode* pos = SLFind(plist, 3);
if (pos)
{
SLInsert(&plist, pos, 30); //在pos之前插入
}
pos = SLFind(plist, 4);
if (pos)
{
SLInsertAfter(pos, 40); //在pos之后插入
}
pos = SLFind(plist, 6);
if (pos)
{
SLErase(&plist, pos); //删除pos位置的值
}
pos = SLFind(plist, 9);
if (pos)
{
SLEraseAfter(pos); //删除pos位置后面的值
}
SLTPrint(plist);
SListDestroy(&plist);
}
int main()
{
test1();
printf("\n");
test2();
printf("\n");
test3();
printf("\n");
return 0;
}
4、单链表OJ题
(3)链表的中间结点
/*
struct ListNode {
int val;
struct ListNode *next;
}; */
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
(6)链表分割
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x)
{
struct ListNode* lesshead, * lesstail, * greaterhead, * greatertail;
lesshead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode));
greaterhead = greatertail = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* cur = pHead;
while (cur)
{
if (cur->val < x)
{
lesstail->next = cur;
lesstail = cur;
}
else
{
greatertail->next = cur;
greatertail = cur;
}
cur = cur->next;
}
lesstail->next = greaterhead->next;
greatertail->next = NULL; //注意greatertail->next可能指向的还是该数在原链表的下一个结点,故要置空
pHead = lesshead->next;
free(lesshead); //lesshead相当于哨兵位
free(greaterhead); //greaterhead相当于哨兵位
return pHead;
}
};
(7)链表的回文结构
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
//链表逆置
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur = head;
struct ListNode* rhead = NULL;
while (cur)
{
struct ListNode* next = cur->next;
//在rhead前头插
cur->next = rhead;
rhead = cur;
//迭代
cur = next;
}
return rhead;
}
//返回链表中间结点
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
bool chkPalindrome(ListNode* head)
{
struct ListNode* mid = middleNode(head);
struct ListNode* rmid = reverseList(mid);
while (rmid)
{
if (head->val != rmid->val)
{
return false;
}
else
{
rmid = rmid->next;
head = head->next;
}
}
return true;
}
};