像写单链表的一些功能接口一样,先来写一些双链表的接口熟悉一下它的主体框架:
#include<stdio.h>
#include<stdlib.h>
typedef int LDataType;
//双向带头循环链表的节点
typedef struct ListNode{
LDataType _data;
//指向下一个节点的起始位置
struct ListNode* _next;
//指向上一个节点的起始位置
struct LIst* _prev;
}ListNode;
//双向带头循环链表
typedef struct List{
struct ListNode* _head;
}List;
struct ListNode* createListNode(LDataType val){
struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->_data = val;
node->_next = NULL;
node->_prev = NULL;
}
void ListInit(List* lst){
//空链表
lst->_head = createListNode(0);
lst->_head->_next = lst->_head->_prev = lst->_head;
}
//尾插 O(1) //给头的前面插一个数据ListInsert(lst, lst->_head, val);
void ListpushBack(List* lst, LDataType val){
if (lst == NULL){
return;
struct ListNode* last = lst->_head->_prev;
struct ListNode* newNode = createListNode(val);
//_head ... last newNode
last->_next = newNode;
newNode->_prev = last;
newNode->_next = lst->_head;
lst->_head->_prev = newNode;
}
}
//尾删://删除头的前一个节点 ListErase(lst, lst->_head->_prev);
void ListPopBack(List* lst){
if (lst == NULL)
return;
//判断是否空链表
if (lst->_head->_next == lst->_head)
return;
struct ListNode* last = lst->_head->_prev;
struct ListNode* prev = last->_prev;
free(last);
lst->_head->_prev = prev;
prev->_next = lst->_head;
}
void printList(List* lst){
struct ListNode* cur = lst->_head->_next;
while (cur != lst->_head){
printf("%d", cur->_data);
cur = cur->_next;
}
printf("\n");
}
//头插//ListInsert(lst,lst->_head->_next,val);
void ListPushFront(List* lst, LDataType val){
if (lst == NULL)
return;
struct ListNode* next = lst->_head->_next;
struct ListNode* newNode = createListNode(val);
//_head, newNode, next
lst->_head->_next = newNode;
newNode->_prev = lst->_head;
newNode->_next = next;
next->_prev = newNode;
}
//头删//ListErase(lst,lst->_head->_next);
void ListPopFront(List* lst){
if (lst == NULL || lst->_head == lst->_head)
return;
struct ListNode* next = lst->_head->_next;
struct ListNode* nextnext = next->_next;
nextnext->_prev = next->_next;
lst->_head->_next = nextnext;
free(next);
}
void ListErase(List* lst, struct ListNode* node){
//不能删除head节点
if (lst == NULL || lst->_head == node)
return;
//prev, node, next
struct ListNode* prev = node->_prev;
struct ListNode* next = node->_next;
prev->_next = next;
next->_prev = prev;
free(node);
}
void ListInsert(List* lst, struct ListNode* node, LDataType val){
if (lst == NULL)
return;
struct ListNode* prev = node->_prev;
struct ListNode* newNode = createListNode(val);
//prev newNode node
prev->_next = newNode;
newNode->_prev = prev;
newNode->_next = node;
node->_prev = newNode;
}
//销毁
ListDestoty(List* lst){
if (lst){
if (lst->_head){
struct ListNode* cur = lst->_head->_next;
while (cur != lst->_head){
struct ListNode* next = cut->_next;
free(cur);
cur = next;
}
free(lst->_head);
}
}
}
void test(){
List lst;
ListInit(&lst);
ListPushFront(&lst, 5);
printList(&lst);
ListPushFront(&lst, 1);
printList(&lst);
ListPushFront(&lst, 2);
printList(&lst);
ListPushFront(&lst, 3);
printList(&lst);
ListPushFront(&lst, 4);
printList(&lst);
ListPopFront(&lst);
printList(&lst);
ListPopFront(&lst);
printList(&lst);
ListPopFront(&lst);
printList(&lst);
/*ListPopBack(&lst);
printList(&lst);
ListPopBack(&lst);
printList(&lst);
ListPopBack(&lst);
printList(&lst);
ListPopBack(&lst);
printList(&lst);*/
}
int main(){
test();
system("pause");
return 0;
}
顺序表和链表的区别和联系:
顺序表优劣:优:空间连续,支持随机访问,空间利用率高不容易造成内存碎片,尾插尾删效率高.
劣:1.中间或前面部分插入删除时间复杂度O(N) 2.增容的代价比较大:申请 拷贝 释放
链表的优劣(带头双向随机链表)
优:1.任意位置插入删除时间复杂度O(1) 2.没有增容问题,插入一个开辟一个空间,任意位置插入删除效率高
劣:以节点为单位存储,不支持随机访问,空间利用率低容易造成内存碎片
栈和队列
栈:一种特殊的线性表,其只允许固定在一端进行插入和删除元素操作.进行数据插入和删除操作的一端叫做栈顶,另一端称为栈底.栈中的数据遵守后进先出LIFO(last in first out)原则
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈,出数据也在栈顶
压栈操作的实现push--->从栈顶存入元素
顺序表:可以把它看成是一个尾插操作
链表:(双向带头循环链表)表头看做栈顶就是头插,表尾看做栈顶就是尾插
出栈操作pop--->从栈顶取出元素
顺序表:表尾看做栈顶,把它看成尾删操作
链表:(双向带头循环链表)表头看做栈顶就是头删,表尾看做栈顶就是尾删
#include<stdio.h>
#include<stdlib.h>
typedef int STDataType;
//顺序表实现一个栈
typedef struct stack{
STDataType* _data;
int _size;
int _capacity;
}stack;
void stackInit(stack* st){
if (st == NULL)
return;
st->_data = NULL;
st->_size = st->_capacity = 0;
}
void checkCapcacity(stack* st){
if (st->_size == st->_capacity){
int newCapcacity = st->_capacity == 0 ? 1 : 2 * st->_capacity;
st->_data = (STDataType*)realloc(st->_data, sizeof(STDataType)* newCapcacity);
st->_capacity = newCapcacity;
}
}
//入栈
void stackPush(stack* st, STDataType val){
if (st == NULL)
return;
checkCapacity(st);
//尾插
st->_data[st->_size++] = val;
}
//出栈
void stackPop(stack* st){
if (st == NULL)
return;
if (st->_size > 0)
st->_size--;
}
STDataType stackTop(stack* st){
return st->_data[st->_size - 1];
}
int stackSize(stack* st){
if (st == NULL)
return 0;
return st->_size;
}
void test(){
stack st;
stackInit(&st);
stackPush(&st, 1);
stackPush(&st, 2);
stackPush(&st, 3);
stackPush(&st, 4);
for (int i = 0; i < 4; ++i){
printg("%d", stackTop(&st));
stackPop(&st);
}
printf("\n");
}
int main(){
test();
system("pause");
return 0;
}