前言
链表的类型有很多种(根据带头或不带头,循环或非循环等等),但是我们重点研究的只有两种,一种结构非常简单是无头单向非循环链表,有关它的操作见
这种结果在开发中基本不会使用,因为因为结构简单往往意味着操作复杂,比如在求职中OJ题,有关链表的基本都用的是这种结构,关于这些OJ题感兴趣的见
另一种则是链表中结构最为复杂的——带头结点的双向循环链表
这种结构看起来确实是很复杂的,但是它的操作很简单,比如最常用的尾插操作,其时间复杂度为O(1)。同时C++中STL中的list就是这种结构
对于这种结构,由于它的带了头结点,所以能使大部分操作使用相同代码实现,如头插等等,又因为它是循环的,所以方便了尾插等操作
注意其链表的空的判断情况
head->prev=head
haed->next=head
实现
(1)结构定义
typedef struct DListNode
{
struct ListNode* next;//指向前一个结点
struct ListNode* prev;//指向后一个结点
DLdatatype val;
}DListNode;
(2)基本函数
1:申请结点、
2:打印
对于打印稍加注意,在这种结构中是没有NULL的,也就是判断结束的条件不能去找NULL,而是要找头
(3)操作实现
1:尾插
2:尾删
3:头插
4:头删
5:找结点
6:任意位置插入(某节点之后)
7:在任意位置插入(某节点之前)
8:任意位置删除
9:销毁
测试
代码
Dlist.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int DLdatatype;
typedef struct DListNode
{
struct DListNode* next;
struct DListNode* prev;
DLdatatype val;
}DListNode;
void printlist(DListNode* head);//打印
DListNode* CreatNode(DLdatatype x);//申请结点
void ListPushBack(DListNode* head, DLdatatype x);//尾插
void ListPopBack(DListNode* head);//尾删
void listPushFront(DListNode* head, DLdatatype x);//头插
void listPopFront(DListNode* head);//头删
DListNode* find(DListNode* head, DLdatatype x);//找某个元素
void listinseret_behind(DListNode* head,DLdatatype pos, DLdatatype x);//任意位置插入(后面)
void listinseret_front(DListNode* head,DLdatatype pos, DLdatatype x);//任意位置插入(前面)
void listdelete(DListNode* head,DLdatatype pos);//任意位置删除
void listdestory(DListNode* head);//链表销毁
Dlist.c
#include "DList.h"
DListNode* CreatNode(DLdatatype x)
{
DListNode* NewNode = (DListNode*)malloc(sizeof(DListNode));
NewNode->val = x;
NewNode->next = NULL;
NewNode->prev = NULL;
return NewNode;
}
void printlist(DListNode* head)
{
assert(head);
DListNode* cur = head->next;
while (cur!=head)
{
printf("%d->", cur->val);
cur = cur->next;
}
if (head->next == head)
printf("NULL");
}
void ListPushBack(DListNode* head, DLdatatype x)
{
assert(head);
DListNode* NewNode=CreatNode(x);
NewNode->next = head;
(head->prev)->next = NewNode;
NewNode->prev = head->prev;
head->prev = NewNode;
}
void ListPopBack(DListNode* head)
{
assert(head);
assert(head->next != head);//如果链表为空,断言
DListNode* delelte = head->prev;
head->prev = delelte->prev;
delelte->prev->next = head;
free(delelte);
}
void listPushFront(DListNode* head, DLdatatype x)
{
assert(head);
DListNode* NewNode = CreatNode(x);
NewNode->next = head->next;
NewNode->prev = head;
head->next->prev = NewNode;
head->next = NewNode;
}
void listPopFront(DListNode* head)
{
assert(head);
assert(head->next != head);
DListNode* first = head->next;
first->next->prev = head;
head->next = first->next;
free(first);
}
DListNode* find(DListNode* head, DLdatatype x)
{
assert(head);
DListNode* cur = head->next;
while (cur->next != head && cur->val != x)
{
cur = cur->next;
}
if (cur->next == head && cur->val!=x)
{
return NULL;//未找到
}
else
{
return cur;//否则返回
}
}
void listinseret_behind(DListNode* head, DLdatatype pos, DLdatatype x)
{
assert(head);
DListNode* insert = find(head, pos);
if (insert == NULL)
{
printf("%d不存在\n", pos);
}
else
{
DListNode* NewNode = CreatNode(x);
NewNode->next = insert->next;
NewNode->prev = insert;
insert->next->prev = NewNode;
insert->next = NewNode;
}
}
void listinseret_front(DListNode* head, DLdatatype pos, DLdatatype x)
{
assert(head);
DListNode* insert = find(head, pos);
if (insert == NULL)
{
printf("%d不存在\n", pos);
}
{
DListNode* NewNode = CreatNode(x);
NewNode->next = insert;
NewNode->prev = insert->prev;
NewNode->prev->next = NewNode;
insert->prev = NewNode;
}
}
void listdelete(DListNode* head, DLdatatype pos)
{
assert(head);
assert(pos != head);
DListNode* delete = find(head, pos);
if (delete == NULL)
{
printf("%d不存在\n", pos);
}
else
{
delete->prev->next = delete->next;
delete->next->prev = delete->prev;
free(delete);
}
}
void listdestory(DListNode* head)
{
assert(head);
DListNode* cur = head->next;
DListNode* pre = NULL;
while (cur->next != head)
{
pre = cur;
cur = cur->next;
free(pre);
}
head->next =head;
head->prev = head;
}
test.c
#include "DList.h"
void test()
{
DListNode* head=(DListNode*)malloc(sizeof(DListNode));
head->prev = head;
head->next = head;
printf("尾插4个结点\n");
ListPushBack(head, 1);
ListPushBack(head, 2);
ListPushBack(head, 3);
ListPushBack(head, 4);
printlist(head);
printf("\n");
printf("\n");
printf("尾删2个结点\n");
ListPopBack(head);
ListPopBack(head);
printlist(head);
printf("\n");
printf("\n");
printf("头插4个结点\n");
listPushFront(head, 5);
listPushFront(head, 6);
listPushFront(head, 7);
listPushFront(head, 8);
printlist(head);
printf("\n");
printf("\n");
printf("头删2个结点\n");
listPopFront(head);
listPopFront(head);
printlist(head);
printf("\n");
printf("\n");
printf("在5后面插入7\n");
listinseret_behind(head, 5, 7);
printlist(head);
printf("\n");
printf("\n");
printf("删除1\n");
listdelete(head, 1);
printlist(head);
printf("\n");
printf("\n");
printf("销毁\n");
listdestory(head);
printlist(head);
printf("\n");
printf("\n");
}
int main()
{
test();
}