顺序表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/86717082
单向链表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/89472595
《一》 双向链表
双向链表思想 : 结构最复杂,一般用在单独储存数据,实际中使用的链表数据结构,都是带头双向链表循环链表,,虽然这个链表看起来比较复杂,但是实现代码之后,这个结构可以解决很多问题,也有很多优势,实现就反而简单了。
下面我们就看一下代码的实现。
首先和之前一样,我们先给出实现的接口;
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<malloc.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
typedef struct List
{
ListNode* _head;
}List;
void ListInit(List* plist); //创建一个链表
void ListDestory(List* plist); //消除一个链表
void ListPushBack(List* plist, LTDataType x); //尾插
void ListPopBack(List* plist); //尾删
void ListPushFront(List* plist, LTDataType x); //头插
void ListPopFront(List* plist); //头删
ListNode* ListFind(List* plist, LTDataType x); //查找
// 在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 删除pos位置的节点
void ListErase(ListNode* pos);
void ListRemove(List* plist, LTDataType x); //移除
int ListSize(List* plist); //节点个数
int ListEmpty(List* plist); // 清空
void ListReverse(List* plist); //相反链表
void ListPrint(List* plist);
还是在这里说明一下,如果有想法的同学,自己还是可以实现以下的,思想很重要。
下面是我的实现代码:
#include"Slist.h"
ListNode*BuyListNode(LTDataType x)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->_data = x;
node->_next = NULL;
node->_prev = NULL;
return node;
}
void ListInit(List* plist) //构建链表
{
ListNode* head = BuyListNode(-1);
assert(plist);
head->_next = head;
head->_prev = head;
plist->_head = head;
}
void ListDestory(List* plist) //判断链表
{
ListNode* head = plist->_head;
ListNode* cur = head->_next;
ListNode* next = NULL;
assert(plist);
while (cur != head)
{
next = cur->_next;
free(cur);
cur = cur->_next;
}
free(head);
head = NULL;
}
void ListPushBack(List* plist, LTDataType x) //尾插
{
ListNode*head = plist->_head;
ListNode* tail = head->_prev;
ListNode* newnode = BuyListNode(x);
assert(plist);
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = head;
head->_prev = newnode;
}
void ListPopBack(List* plist) //尾删
{
ListNode*head = plist->_head;
ListNode* tail = head->_prev;
ListNode* tailprev = tail->_prev;
assert(plist);
free(tail);
tailprev->_next = head;
head->_prev = tailprev;
}
void ListPushFront(List* plist, LTDataType x) //头插
{
ListNode*head = plist->_head;
ListNode* next = head->_next;
ListNode* newnode = BuyListNode(x);
assert(plist);
head->_next = newnode;
newnode->_next = next;
newnode->_prev = head;
next->_prev = newnode;
}
void ListPopFront(List* plist) //头删
{
ListNode* head = plist->_head;
ListNode* next = head->_next;
ListNode* nextnext = next->_next;
assert(plist);
free(next);
head->_next = nextnext;
nextnext->_prev = head;
}
ListNode* ListFind(List* plist, LTDataType x) //查找
{
ListNode* head = plist->_head;
ListNode* cur = head->_next;
assert(plist);
while (cur != head)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return cur;
}
// 在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
ListNode* prev = pos->_prev;
ListNode* newnode = BuyListNode(x);
assert(pos);
newnode->_next = pos;
pos->_prev = newnode;
prev->_next = newnode;
newnode->_prev = prev;
}
// 删除pos位置的节点
void ListErase(ListNode* pos)
{
ListNode* prev = pos->_prev;
ListNode* next = pos->_next;
assert(pos);
free(pos);
prev->_next = next;
next->_prev = prev;
}
void ListRemove(List* plist, LTDataType x) //移除
{
ListNode* node = ListFind(plist, x);
assert(plist);
if (node != plist->_head)
{
ListErase(node);
}
}
int ListSize(List* plist) //节点个数
{
int size = 0;
ListNode* cur = plist->_head->_next;
assert(plist);
while (cur != plist->_head)
{
size++;
cur = cur->_next;
}
printf("%d", size);
return size;
}
int ListEmpty(List* plist) //清空链表
{
assert(plist);
printf("%d", plist->_head->_next == plist->_head ? 0 : -1);
return 0;
}
void ListReverse(List* plist) //反向链表
{
ListNode* head = plist->_head;
ListNode* cur = head->_next;
ListNode* tmp = NULL;
assert(plist);
while (cur != plist->_head)
{
tmp = cur->_next;
cur->_next = cur->_prev;
cur->_prev = tmp;
cur = cur->_prev;
}
tmp = head->_next;
head->_next = head->_prev;
head->_prev = tmp;
}
void ListPrint(List* plist)
{
ListNode* head = plist->_head;
ListNode* cur = head->_next;
assert(plist);
while (cur != head)
{
printf("<-%d->", cur->_data);
cur = cur->_next;
}
printf("\n");
}
这里就是我们所实现的接口代码。上面的尾插,尾删,头插,头删,头可以用 Insert,Erase,替换,来使代码的复量减小,简单实现,就可以使用那样的想法。
下面我们再看看,函数调用的接口
#include"Slist.h"
int main()
{
List s;
ListInit(&s);
ListPushBack(&s, 1);
ListPushBack(&s, 2);
ListPushBack(&s, 3);
ListPushBack(&s, 4);
ListPushBack(&s, 5);
ListPushBack(&s, 6);
ListPushBack(&s, 7);
ListPrint(&s);
ListPopBack(&s);
ListPrint(&s);
ListPushFront(&s, 0);
ListPrint(&s);
ListPopFront(&s);
ListPrint(&s);
ListRemove(&s, 3);
ListPrint(&s);
ListNode* pos = ListFind(&s, 5);
ListInsert(pos, 30);
ListPrint(&s);
ListErase(pos);
ListPrint(&s);
ListReverse(&s);
ListPrint(&s);
}
上面的就是我们所实现的双向链表的接口,以及实现代码,下来我们再看看执行结果。
最后,我还想把链表和顺序表比较一下,
《一》 顺序表:一白遮百丑
白:空间连续、支持随机访问
丑:1.中间或前面部分的插入删除时间复杂度O(N)
2.增容的代价比较大。
《二》 链表:一(胖黑)毁所有
胖黑:以节点为单位存储,不支持随机访问
所有:1.任意位置插入删除时间复杂度为O(1)
2.没有增容问题,插入一个开辟一个空间。
顺序表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/86717082
单向链表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/89472595