赞
踩
作为计算机领域的核心基础理论学科之一——数据结构,其讨论研究的主要相关内容为,数据是如何在内存中进行存储与管理的;我们知道,应用程序(.exe文件)在运行时,会将存储在磁盘中的数据读入到内存中,再进行相应的处理操作;而在这一过程中,数据在内存中的存储组织方式就显得十分的重要啦;在算法中,根据实际业务需求,采用合适的数据组织方式,能极大地发挥出算法的威力,提高算法的性能。而笔者今天的内容,主要是对近期学习线性表这一数据结构知识的总结与梳理,内容如下:
线性表(linear list): 是n个具有相同特性数据元素的有限序列。
常见的线性表:
值得注意的是:线性表在逻辑上是连续的,但在物理存储结构上不一定是连续的,如链表。
顺序表:用一段物理地址连续的存储单元依次存储数据元素的线性结构
常见顺序表:
支持动态增长的顺序表实现
SeqList.h :类型与函数的声明
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
-
- #define __DEBUG__ 0
-
- // 静态顺序表
- #if __DEBUG__
- #define N 100 // 定长数组的大小
- typedef int SLDdataType; // 重命名顺序表的数据类型
-
- struct SeqList
- {
- SLDdataType a[N]; // 定长数组
- int size; // 已存储的数据个数
- };
- #endif
-
- // 动态顺序表
- typedef int SLDataType;
-
- typedef struct SeqList
- {
- SLDataType* a; // 指向动态开辟的数组
- int size; // 有效的数据个数
- int capacity; // 动态数组的容量
- }SL;
-
- // 功能操作
- void SeqListInit(SL* ps); // 初始化
- void SeqListPrint(SL* ps); // 打印
- void SeqListDestory(SL* ps); // 销毁
- void SeqListCheckCapacity(SL* ps); // 检查容量
- void SeqListPushBack(SL* ps, SLDataType x); // 尾插
- void SeqListPopBack(SL* ps); // 尾删
- void SeqListPushFront(SL* ps, SLDataType x); // 头插
- void SeqListPopFront(SL* ps); // 头删
- void SeqListInsert(SL* ps, int pos, SLDataType x); // 任意位置插入
- void SeqListErase(SL* ps, int pos); // 任意位置删除
- void SeqListModify(SL* ps, int pos, SLDataType x); // 修改
- int SeqListFind(SL* ps, SLDataType x); // 查找

SeqList.c : 功能实现
- #include "SeqList.h"
-
- // 初始化
- void SeqListInit(SL* ps)
- {
- assert(ps);
- ps->a = NULL;
- ps->size = 0;
- ps->capacity = 0;
- }
-
- // 销毁
- void SeqListDestory(SL* ps)
- {
- if (ps->a)
- {
- free(ps->a);
- ps->a = NULL;
- ps->capacity = ps->size = 0;
- }
- }
-
- // 打印
- void SeqListPrint(SL* ps)
- {
- assert(ps);
- int i = 0;
- for (i = 0; i < ps->size; i++)
- {
- printf("%d ", ps->a[i]);
- }
- printf("\n");
- }
-
- // 扩容
- void SeqListCheckCapacity(SL* ps)
- {
- assert(ps);
-
- if (ps->size == ps->capacity)
- {
- int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
- SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
- if (tmp != NULL)
- {
- ps->a = tmp;
- }
- else
- {
- perror("CheckCapacity::realloc\n");
- exit(-1);
- }
- ps->capacity = newCapacity;
- }
- }
-
- // 尾插
- void SeqListPushBack(SL* ps, SLDataType x)
- {
- SeqListInsert(ps, ps->size, x);
- //assert(ps);
- 检查容量空间
- //SeqListCheckCapacity(ps);
-
- //ps->a[ps->size] = x;
- //ps->size++;
- }
-
- // 头插
- void SeqListPushFront(SL* ps, SLDataType x)
- {
- SeqListInsert(ps, 0, x);
- //assert(ps);
- //SeqListCheckCapacity(ps);
-
- 挪动数据
- //int end = ps->size - 1;
- //while (end >= 0)
- //{
- // ps->a[end + 1] = ps->a[end];
- // end--;
- //}
- //ps->a[0] = x;
- //ps->size++;
- }
-
- // 尾删
- void SeqListPopBack(SL* ps)
- {
- SeqListErase(ps, ps->size - 1);
- //assert(ps);
-
- 暴力检查
- //assert(ps->size);
- ps->size--;
- 避免越界访问越界访问
- //if (ps->size)
- //{
- // ps->size--;
- //}
- //else
- //{
- // printf("SeqList is already empty"); // 温柔检查
- // exit(-1);
- //}
-
- }
-
- // 头删
- void SeqListPopFront(SL* ps)
- {
- SeqListErase(ps, 0);
- //assert(ps);
-
- //assert(ps->size);
- //int i = 0;
- //if (ps->size)
- //{
- // for (i = 0; i < ps->size - 1; i++)
- // {
- // ps->a[i] = ps->a[i + 1];
- // }
- // ps->size--;
- //}
- //else
- //{
- // printf("SeqList is already empty"); // 温柔检查
- // exit(-1);
- //}
- }
-
- // 任意位置插入
- void SeqListInsert(SL* ps, int pos, SLDataType x)
- {
- // 防御式检查
- assert(ps);
- assert(pos >= 0 && pos <= ps->size);
- SeqListCheckCapacity(ps);
- int end = ps->size - 1;
- while (end >= pos)
- {
- ps->a[end + 1] = ps->a[end];
- end--;
- }
- ps->a[pos] = x;
- ps->size++;
- }
-
- // 任意位置删除
- void SeqListErase(SL* ps, int pos)
- {
- assert(ps);
- assert(pos >= 0 && pos < ps->size);
-
- int begin = pos;
- while (begin < ps->size-1) // 边界控制
- {
- ps->a[begin] = ps->a[begin + 1];
- begin++;
- }
- ps->size--;
- }
-
- // 查找
- int SeqListFind(SL* ps, SLDataType x)
- {
- assert(ps);
-
- int i = 0;
- for (i = 0; i < ps->size; i++)
- {
- if (ps->a[i] == x)
- {
- return i; // 返回下标
- }
- }
- return -1;
- }
-
- // 修改
- void SeqListModify(SL* ps, int pos, SLDataType x)
- {
- assert(ps);
- assert(pos >= 0 && pos < ps->size);
- ps->a[pos] = x;
- }

New.c : 功能测试
- #include "SeqList.h"
-
- void Test1()
- {
- SL s1;
- SeqListInit(&s1);
- SeqListPushBack(&s1, 1);
- SeqListPushBack(&s1, 2);
- SeqListPushBack(&s1, 3);
- SeqListPushBack(&s1, 4);
- SeqListPrint(&s1);
- SeqListPushBack(&s1, 5);
- SeqListPushBack(&s1, 4);
- SeqListPushBack(&s1, 3);
- SeqListPushBack(&s1, 2);
- SeqListPushBack(&s1, 1);
- SeqListPrint(&s1);
- }
-
- void Test2()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(&s1, 5);
- SeqListPushFront(&s1, 4);
- SeqListPushFront(&s1, 3);
- SeqListPushFront(&s1, 2);
- SeqListPushFront(&s1, 1);
- SeqListPrint(ps);
- SeqListPushBack(&s1, 4);
- SeqListPushBack(&s1, 3);
- SeqListPushBack(&s1, 2);
- SeqListPushBack(&s1, 1);
- SeqListPrint(ps);
-
- }
-
- void Test3()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(ps, 5);
- SeqListPushFront(ps, 4);
- SeqListPushFront(ps, 3);
- SeqListPushFront(ps, 2);
- SeqListPushFront(ps, 1);
- SeqListPrint(ps);
- SeqListPopBack(ps);
- SeqListPopBack(ps);
- SeqListPopBack(ps);
- SeqListPopBack(ps);
- SeqListPopBack(ps);
- SeqListPopBack(ps);
- SeqListPopBack(ps);
- SeqListPushFront(ps, 2);
- SeqListPushFront(ps, 3);
- SeqListPushFront(ps, 2);
-
- SeqListPrint(ps);
- SeqListDestory(ps);
- }
-
- void Test4()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(&s1, 5);
- SeqListPushFront(&s1, 4);
- SeqListPushFront(&s1, 3);
- SeqListPushFront(&s1, 2);
- SeqListPushFront(&s1, 1);
- SeqListPrint(ps);
- SeqListPopFront(ps);
- SeqListPopFront(ps);
- SeqListPopFront(ps);
- SeqListPopFront(ps);
- SeqListPopFront(ps);
- SeqListPopFront(ps);
- SeqListPopFront(ps);
- SeqListPrint(ps);
- }
-
- void Test5()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(&s1, 5);
- SeqListPushFront(&s1, 4);
- SeqListPushFront(&s1, 3);
- SeqListPushFront(&s1, 2);
- SeqListPushFront(&s1, 1);
- SeqListPrint(ps);
- SeqListInsert(ps, 0, 8);
- SeqListPrint(ps);
- }
-
- void Test6()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(&s1, 5);
- SeqListPushFront(&s1, 4);
- SeqListPushFront(&s1, 3);
- SeqListPushFront(&s1, 2);
- SeqListPushFront(&s1, 1);
- SeqListPrint(ps);
- SeqListErase(ps, 2);
- SeqListPrint(ps);
- SeqListErase(ps, 0);
- SeqListPrint(ps);
- SeqListErase(ps, ps->size-1);
- SeqListPrint(ps);
- SeqListPopFront(ps);
- SeqListPushFront(ps, 6);
- SeqListPrint(ps);
- SeqListPopBack(ps);
- SeqListPrint(ps);
-
- }
-
- void Test7()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(&s1, 5);
- SeqListPushFront(&s1, 4);
- SeqListPushFront(&s1, 3);
- SeqListPushFront(&s1, 2);
- SeqListPushFront(&s1, 1);
- SeqListPrint(ps);
- int x = 0;
- printf("请输入你要删除的值:> ");
- scanf("%d", &x);
- int pos = SeqListFind(ps, x);
- if (pos != -1)
- {
- SeqListErase(ps, pos);
- }
- else
- {
- printf("没有找到\n");
- }
- SeqListPrint(ps);
-
- }
-
- void Test8()
- {
- SL s1;
- SL* ps = &s1;
- SeqListInit(ps);
- SeqListPushFront(&s1, 5);
- SeqListPushFront(&s1, 4);
- SeqListPushFront(&s1, 3);
- SeqListPushFront(&s1, 2);
- SeqListPushFront(&s1, 1);
- SeqListPrint(ps);
- int y = 0;
- int z = 0;
- printf("请输入你要修改的值和修改之后的值:> ");
- scanf("%d %d", &y, &z);
- int pos = SeqListFind(ps, y);
- if (pos != -1)
- {
- SeqListModify(ps, pos, z);
- }
- else
- {
- printf("没有找到\n");
- }
- SeqListPrint(ps);
- }
-
- int main()
- {
- //Test1();
- //Test2();
- //Test3();
- //Test4();
- //Test5();
- //Test6();
- //Test7();
- Test8();
- return 0;
- }

链表:物理存储非连续,数据存储的逻辑顺序是连续的线性存储结构
常见链表:
无头单向非循环链表的实现
SList.h : 功能与类型的声明
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
-
- typedef int SLDataType;
-
- typedef struct SListNode
- {
- SLDataType data; // 存储的数据
- struct SListNode* next; // 指向下一个节点
- }SLNode;
-
-
- void SListPrint(SLNode* phead); // 打印
- SLNode* CreateSListNode(SLDataType* x); // 创建新节点
- void SListPushBack(SLNode** pphead, SLDataType x); // 尾插
- void SListPushFront(SLNode** pphead, SLDataType x); // 头插
- void SListPopBack(SLNode** pphead); // 尾删
- void SListPopFront(SLNode** pphead); // 头删
- SLNode* SListFind(SLNode* phead, SLDataType x); // 查找
- void SListModify(SLNode* pos, SLDataType x, SLDataType y); // 修改
- void SListInsert(SLNode** pphead, SLNode* pos, SLDataType x); // 在指定位置之前插入
- void SListInsertAfter(SLNode* pos, SLDataType x); // 在指定位置之后插入
- void SListErase(SLNode** pphead, SLNode* pos); // 删除指定位置的节点
- void SListEraseAfter(SLNode* pos); // 在指定位置之后删除

SList.c : 功能实现
- #include"SList.h"
-
- // 打印
- void SListPrint(SLNode* phead)
- {
- SLNode* cur = phead;
- while (cur)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
-
- // 创建新节点
- SLNode* CreateSListNode(SLDataType* x)
- {
- SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
- assert(newnode);
-
- newnode->data = x;
- newnode->next = NULL;
-
- return newnode;
- }
-
- // 尾插 想改变外部的指针(实参),就需要传入指针的地址;想在函数中改变外部变量(实参)的内容,就需要传入该外部变量的地址
- // 因为函数的形参只是实参的一份临时拷贝,与实参没有直接联系,只是模拟实参的效果,形参的改变对实参没有直接的影响
- void SListPushBack(SLNode** pphead, SLDataType x)
- {
- assert(pphead);
- // 允许空链表传入
- SLNode* cur = *pphead;
- SLNode* newnode = CreateSListNode(x);
-
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- else
- {
- while (cur->next) // 找尾节点
- {
- cur = cur->next;
- }
-
- cur->next = newnode;
- }
- // 只有当节点不被需要了,才进行free操作
- // 函数结束,函数中定义的局部变量被销毁,但malloc的内存空间依旧存在有效
- }
-
- // 头插 使用二级指针,与外部的phead建立直接的联系,头插完成之后,phead要指向新的头节点
- void SListPushFront(SLNode** pphead, SLDataType x)
- {
- assert(pphead);
- // 允许空链表传入
- /*assert(*pphead);*/
- SLNode* cur = *pphead;
- SLNode* newnode = CreateSListNode(x);
-
- newnode->next = cur;
- *pphead = newnode;
- }
-
- // 尾删
- void SListPopBack(SLNode** pphead)
- {
- assert(pphead);
- // 链表本就为空,就不能再进行删除了
- assert(*pphead);
-
- // 只有一个节点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL; // 改变了phead指针的值,所以要传二级指针
- }
- else // 多个节点
- {
- // 找尾节点的前一个节点
- SLNode* prev = *pphead;
- while (prev->next->next) // 当只有一个节点时,会有越界访问的问题
- {
- prev = prev->next;
- }
- SLNode* tail = prev->next;
- free(tail); // 释放掉tail指针指向的结构体空间; 但只有一个节点时,则会发生释放NULL指针的的错误
- prev->next = NULL; // 将尾节点的前一个节点的next指针,置空
- }
-
- }
-
- // 头删
- void SListPopFront(SLNode** pphead)
- {
- assert(pphead);
- // 链表本就为空,就不能再进行删除了
- assert(*pphead);
- SLNode* next = (*pphead)->next;
- free(*pphead); // 将结构体节点所占用的空间,进行释放,即销毁
- *pphead = next;
- }
-
- // 查找
- SLNode* SListFind(SLNode* phead, SLDataType x)
- {
-
- // 空链表无法进行查找
- assert(phead);
- SLNode* cur = phead;
- while (cur->next) // 逻辑有问题,如果查找的是尾节点,则将尾节点的情况直接跳过而没有进行检查
- {
- if (cur->data == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- if (cur->data == x) // 检查一下跳过的尾节点
- return cur;
- else
- return NULL;
- }
-
- // 修改
- void SListModify(SLNode* phead, SLDataType x, SLDataType y)
- {
- SLNode* cur = SListFind(phead, x);
- if (cur)
- {
- cur->data = y;
- }
- else
- {
- printf("%d不存在\n", x);
- }
- }
-
- // 在pos节点之前插入
- void SListInsert(SLNode** pphead, SLNode* pos, SLDataType x)
- {
- // 以防恶意插入
- assert(pos);
- assert(pphead);
- // 空链表也可以传入
- SLNode* newnode = CreateSListNode(x);
- if (*pphead == NULL)
- {
- newnode->next = *pphead;
- *pphead = newnode;
- }
- else
- {
- // 找到pos节点的前一个节点
- SLNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- newnode->next = pos;
- prev->next = newnode;
- }
- }
-
- // 在pos之后进行插入
- void SListInsertAfter(SLNode* pos, SLDataType x)
- {
- // 以防恶意插入
- assert(pos);
- // 空链表无法进行查找,已在SListFind内进行断言,保证了pos的有效性
- SLNode* newnode = CreateSListNode(x);
-
- newnode->next = pos->next;
- pos->next = newnode;
- }
-
- // 删除指定位置的节点
- void SListErase(SLNode** pphead, SLNode* pos)
- {
- // 以防恶意删除
- assert(pos);
- assert(pphead);
- // 空链表无法进行删除,已在SListFind内进行断言,保证了*phead和pos的有效性
- // 找到pos的前一个节点
- if ((*pphead)->next == NULL) // 只有一个节点时
- {
- free(*pphead);
- *pphead = NULL;
- }
- else if (*pphead == pos) // 有多个节点时,要删除头节点
- {
- *pphead = pos->next;
- free(pos);
- }
- else // 有多个节点时,删除其它节点
- {
- SLNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- prev->next = pos->next;
- free(pos);
- }
- }
-
- // 在指定位置之后删除
- void SListEraseAfter(SLNode* pos)
- {
- // 以防恶意删除
- assert(pos);
- // 空链表无法进行删除,已在SListFind内进行断言,pos的有效性
- if (pos->next == NULL) // pos已为尾节点
- {
- return;
- }
- else
- {
- SLNode* after = pos->next->next;
- free(pos->next);
- pos->next = after;
- }
- }

New.c : 功能测试
- #include "SList.h"
-
- void Test1()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- }
-
- void Test2()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
-
- SListPushBack(&n1, 5);
- SListPrint(&n1);
- SListPushBack(&n1, 4);
- SListPushBack(&n1, 3);
- SListPushBack(&n1, 2);
- SListPushBack(&n1, 1);
- SListPrint(n1);
-
- }
-
- void Test3()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SListPushFront(&n1, 0);
- SListPushFront(&n1, -1);
- SListPushFront(&n1, -2);
- SListPushFront(&n1, -3);
- SListPushFront(&n1, -4);
-
- SListPrint(n1);
-
- }
-
- void Test4()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode** pphead = &n1;
- SListPopFront(pphead);
- SListPopFront(pphead);
- SListPopFront(pphead);
- SListPopFront(pphead);
- SListPopFront(pphead);
-
- SListPrint(n1);
-
- }
-
- void Test5()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode** pphead = &n1;
- SListPopBack(pphead);
- SListPrint(n1);
- SListPopBack(pphead);
- SListPrint(n1);
- SListPopBack(pphead);
- SListPrint(n1);
- SListPopBack(pphead);
-
- SListPrint(n1);
- }
-
- void Test6()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode* phead = n1;
- int x = 0;
- int y = 0;
- printf("请输入要修改的值和修改之后的值:> ");
- scanf("%d %d", &x, &y);
- SListModify(phead, x, y);
- SListPrint(n1);
- }
- void Test7()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode* phead = n1;
- SLNode** pphead = &n1;
- int x = 0;
- int y = 0;
- printf("输入指定的插入位置与要插入的数字(在该位置之前插入):> ");
- scanf("%d %d", &x, &y);
- SLNode* pos = SListFind(phead, x);
- SListInsert(pphead, pos, y);
- SListPrint(n1);
-
- }
-
- void Test8()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode* phead = n1;
- SLNode** pphead = &n1;
- int x = 0;
- int y = 0;
- printf("输入指定的插入位置与要插入的数字(在该位置之后插入):> ");
- scanf("%d %d", &x, &y);
- SLNode* pos = SListFind(phead, x);
- SListInsertAfter(pos, y);
- SListPrint(n1);
-
- }
-
- void Test9()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode* phead = n1;
- SLNode** pphead = &n1;
- int x = 0;
- printf("输入要删除的数字:> ");
- scanf("%d", &x);
- SLNode* pos = SListFind(phead, x);
- SListErase(pphead, pos);
- SListPrint(n1);
- }
-
- void Test10()
- {
- SLNode* n1 = (SLNode*)malloc(sizeof(SLNode));
- assert(n1);
-
- SLNode* n2 = (SLNode*)malloc(sizeof(SLNode));
- assert(n2);
-
- SLNode* n3 = (SLNode*)malloc(sizeof(SLNode));
- assert(n3);
-
- SLNode* n4 = (SLNode*)malloc(sizeof(SLNode));
- assert(n4);
-
- n1->data = 1;
- n2->data = 2;
- n3->data = 3;
- n4->data = 4;
-
- n1->next = n2;
- n2->next = n3;
- n3->next = n4;
- n4->next = NULL;
- SListPrint(n1);
- SLNode* phead = n1;
- SLNode** pphead = &n1;
- int x = 0;
- printf("输入所删除数字的前一个数字:> ");
- scanf("%d", &x);
- SLNode* pos = SListFind(phead, x);
- SListEraseAfter(pos);
- SListPrint(n1);
- }
-
- int main()
- {
- //Test1();
- //Test2();
- //Test3();
- //Test4();
- //Test5();
- //Test6();
- //Test7();
- //Test8();
- //Test9();
- Test10();
- return 0;
- }

带头双向循环链表的实现
DList.h :功能与类型的声明
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<stdbool.h>
- #include<assert.h>
-
-
- typedef int LTDataType;
-
- typedef struct ListNode
- {
- struct ListNode* next; // 后继指针
- struct ListNode* prev; // 前驱指针
- LTDataType data;
- }LTNode;
-
-
- LTNode* ListInit(); // 初始化
- void ListPrint(LTNode* phead); // 打印
- void ListPushBack(LTNode* phead, LTDataType x); // 尾插
- void ListPushFront(LTNode* phead, LTDataType x); // 头插
- void ListPopBack(LTNode* phead); // 尾删
- void ListPopFront(LTNode* phead); // 头删
- bool ListEmpty(LTNode* phead); // 判断链表是否为空
- LTNode* ListFind(LTNode* phead, LTDataType x); // 查找
- void ListInsert(LTNode* pos, LTDataType x); // 在pos位置之前插入
- void ListErase(LTNode* pos); // 删除pos位置的节点
- int ListSize(LTNode* phead); // 统计链表有效节点的个数
- void ListDestory(LTNode* phead); // 销毁链表

DList.c : 功能实现
- #include "DList.h"
-
- LTNode* CreateListNode(LTDataType x)
- {
- LTNode* node = (LTNode*)malloc(sizeof(LTNode));
- if (node == NULL)
- {
- perror("CreateListNode:: malloc");
- exit(-1);
- }
-
- node->data = x;
- node->next = NULL;
- node->prev = NULL;
- return node;
- }
-
- // 初始化链表
- LTNode* ListInit()
- {
- LTNode* phead = CreateListNode(-1);
- phead->next = phead;
- phead->prev = phead;
- return phead;
- }
-
- // 打印
- void ListPrint(LTNode* phead)
- {
- assert(phead);
- LTNode* cur = phead->next;
- while (cur != phead)
- {
- printf("%d ", cur->data);
- cur = cur->next;
- }
- printf("\n");
- }
-
- // 尾插
- void ListPushBack(LTNode* phead, LTDataType x)
- {
- assert(phead);
- /*LTNode* newnode = CreateListNode(x);
- LTNode* tail = phead->prev;
- tail->next = newnode;
- newnode->prev = tail;
- phead->prev = newnode;
- newnode->next = phead;*/
-
- ListInsert(phead, x);
- }
-
- // 头插
- void ListPushFront(LTNode* phead, LTDataType x)
- {
- assert(phead);
- /*LTNode* newnode = CreateListNode(x);
- phead->next->prev = newnode;
- newnode->next = phead->next;
- newnode->prev = phead;
- phead->next = newnode;*/
-
- ListInsert(phead->next, x);
- }
-
- // 判断链表是否为空
- bool ListEmpty(LTNode* phead)
- {
- assert(phead);
-
- return phead->next == phead;
- }
-
- // 尾删
- void ListPopBack(LTNode* phead)
- {
- assert(phead);
- assert(phead->prev != phead);
- //LTNode* newtail = phead->prev->prev;
- //LTNode* tail = phead->prev;
-
- //free(tail);
-
- //phead->prev = newtail;
- //newtail->next = phead;
- ListErase(phead->prev);
-
- }
-
- // 头删
- void ListPopFront(LTNode* phead)
- {
- assert(phead);
- assert(phead->prev != phead);
-
- /*LTNode* next = phead->next->next;
- phead->next = next;
- next->prev = phead;*/
- ListErase(phead->next);
- }
-
- // 查找
- LTNode* ListFind(LTNode* phead, LTDataType x)
- {
- assert(phead);
- LTNode* cur = phead->next;
- while (cur != phead)
- {
- if (cur->data == x)
- return cur;
-
- cur = cur->next;
- }
- return NULL;
- }
-
- // 在pos位置之前插入
- void ListInsert(LTNode* pos, LTDataType x)
- {
- LTNode* newnode = CreateListNode(x);
- LTNode* prev = pos->prev;
- prev->next = newnode;
- newnode->prev = prev;
-
- newnode->next = pos;
- pos->prev = newnode;
- }
-
-
- // 删除pos位置的节点
- void ListErase(LTNode* pos)
- {
- LTNode* prev = pos->prev;
- LTNode* next = pos->next;
-
- prev->next = next;
- next->prev = prev;
-
- free(pos);
- }
-
- // 统计链表有效节点的个数
- int ListSize(LTNode* phead)
- {
- assert(phead);
- LTNode* cur = phead->next;
- int size = 0;
- while (cur != phead)
- {
- ++size;
- cur = cur->next;
- }
- return size;
- }
-
- // 销毁链表
- void ListDestory(LTNode* phead)
- {
- assert(phead);
- LTNode* cur = phead->next;
- while (cur != phead)
- {
- LTNode* next = cur->next;
- ListErase(cur);
- cur = next;
- }
- free(phead);
- }

New.c : 功能测试
- #include "DList.h"
- void Test1()
- {
- LTNode* plist = ListInit();
- ListPushBack(plist, 1);
- ListPushBack(plist, 2);
- ListPushBack(plist, 3);
- ListPushBack(plist, 4);
- ListPrint(plist);
- ListPushBack(plist, 5);
- ListPrint(plist);
- }
-
- void Test2()
- {
- LTNode* plist = ListInit();
- ListPushBack(plist, 1);
- ListPushBack(plist, 2);
- ListPushBack(plist, 3);
- ListPushBack(plist, 4);
- ListPrint(plist);
- ListPushFront(plist, 0);
- ListPushFront(plist, -1);
- ListPushFront(plist, -2);
- ListPushFront(plist, -3);
- ListPushFront(plist, -4);
- ListPrint(plist);
- }
-
- void Test3()
- {
- LTNode* plist = ListInit();
- ListPushBack(plist, 1);
- ListPushBack(plist, 2);
- ListPushBack(plist, 3);
- ListPushBack(plist, 4);
- ListPrint(plist);
- ListPushFront(plist, 0);
- ListPushFront(plist, -1);
- ListPushFront(plist, -2);
- ListPushFront(plist, -3);
- ListPushFront(plist, -4);
- ListPrint(plist);
- ListPopBack(plist);
- ListPopBack(plist);
- ListPopBack(plist);
- ListPopBack(plist);
- ListPrint(plist);
-
- }
-
- void Test4()
- {
- LTNode* plist = ListInit();
- ListPushBack(plist, 1);
- ListPushBack(plist, 2);
- ListPushBack(plist, 3);
- ListPushBack(plist, 4);
- ListPrint(plist);
- ListPushBack(plist, 3);
- ListPushBack(plist, 2);
- ListPushBack(plist, 1);
- ListPrint(plist);
- ListPopFront(plist);
- ListPopFront(plist);
- ListPopFront(plist);
- ListPrint(plist);
-
- }
-
- void Test5()
- {
- LTNode* plist = ListInit();
- ListPushBack(plist, 1);
- ListPushBack(plist, 2);
- ListPushBack(plist, 3);
- ListPushBack(plist, 4);
- ListPrint(plist);
- int x = 0;
- int y = 0;
- printf("请输入要插入的位置与要插入的数字(在该节点之前插入):> ");
- scanf("%d %d", &x, &y);
- LTNode* pos = ListFind(plist, x);
- if (pos != NULL)
- {
- ListInsert(pos, y);
- }
- else
- {
- printf("输入不合法\n");
- }
- ListPrint(plist);
-
- }
-
- void Test6()
- {
- LTNode* plist = ListInit();
- ListPushBack(plist, 1);
- ListPushBack(plist, 2);
- ListPushBack(plist, 3);
- ListPushBack(plist, 4);
- ListPrint(plist);
- int x = 0;
- printf("请输入要插入的位置:> ");
- scanf("%d", &x);
- LTNode* pos = ListFind(plist, x);
- if (pos != NULL)
- {
- ListErase(pos);
- }
- else
- {
- printf("输入不合法\n");
- }
- ListPrint(plist);
- }
-
- void Test7()
- {
- LTNode* plist = ListInit();
- ListPushFront(plist, 5);
- ListPushFront(plist, 4);
- ListPushFront(plist, 3);
- ListPushFront(plist, 2);
- ListPushFront(plist, 1);
- ListPrint(plist);
- ListPushBack(plist, 4);
- ListPushBack(plist, 3);
- ListPushBack(plist, 2);
- ListPushBack(plist, 1);
- ListPrint(plist);
- ListPopBack(plist);
- ListPrint(plist);
- ListPopFront(plist);
- ListPrint(plist);
-
- }
-
- int main()
- {
- //Test1();
- //Test2();
- //Test3();
- //Test4();
- //Test5();
- //Test6();
- Test7();
- return 0;
- }

栈:只允许在固定的一端进行插入删除元素操作的线性结构 (Last In Frist Out)
栈顶:进行数据插入删除操作的一端
常见栈:
使用支持动态增长循序表实现的栈
Stack.h : 功能与类型的声明
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- #include<stdbool.h>
-
- #define __DEBUG__ 0
-
- // 静态栈的定义
- #if __DEBUG__
- typedef int STDataType;
- #define N 10
- struct Stack
- {
- STDataType a[N];
- int top; // 栈顶
- };
- #endif
-
- // 支持动态增长的栈
- typedef int STDataType;
- typedef struct Stack
- {
- STDataType* a;
- int top; // 栈顶
- int capacity; // 容量
- }Stack;
-
- void StackInit(Stack* ps); // 初始化栈
- void StackPush(Stack* ps, STDataType x); // 入栈
- void StackPop(Stack* ps); // 出栈
- STDataType StackTop(Stack* ps); // 取栈顶的元素
- int StackSize(Stack* ps); // 获取栈中有效元素的个数
- bool StackEmpty(Stack* ps); // 检测栈是否为空
- void StackDestory(Stack* ps); // 销毁栈

Stack.c : 功能实现
- #include "Stack.h"
-
- // 初始化栈
- void StackInit(Stack* ps)
- {
- assert(ps);
- ps->a = NULL;
- ps->capacity = ps->top = 0; // 栈顶的位置无数据
- }
-
- // 检测栈是否为空
- bool StackEmpty(Stack* ps)
- {
- assert(ps);
- return ps->top == 0;
- }
-
- // 入栈
- void StackPush(Stack* ps,STDataType x)
- {
- assert(ps);
- // 检查是否需要扩容
- if (ps->top == ps->capacity)
- {
- int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
- STDataType* new = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
- if (new == NULL)
- {
- perror("StackPush::realloc\n");
- exit(-1);
- }
- ps->a = new;
- ps->capacity = newCapacity;
- }
- ps->a[ps->top] = x;
- ps->top++;
- }
-
- // 出栈
- void StackPop(Stack* ps)
- {
- assert(ps);
- assert(!StackEmpty(ps));
- ps->top--;
- }
-
- // 取栈顶的元素
- STDataType StackTop(Stack* ps)
- {
- assert(ps);
- assert(!StackEmpty(ps));
-
- return ps->a[ps->top - 1];
- }
-
- // 获取栈中有效元素的个数
- int StackSize(Stack* ps)
- {
- assert(ps);
-
- return ps->top;
- }
-
- // 销毁栈
- void StackDestory(Stack* ps)
- {
- assert(ps);
- free(ps->a);
- ps->top = ps->capacity = 0;
- }

New.c : 功能测试
- #include "Stack.h"
- void Test1()
- {
- Stack s;
- Stack* ps = &s;
- StackInit(ps);
- StackPush(ps, 1);
- StackPush(ps, 2);
- StackPush(ps, 3);
- StackPush(ps, 4);
- StackPush(ps, 5);
- int size = 0;
- size = StackSize(ps);
- printf("%d:\n", size);
- while (!StackEmpty(ps))
- {
- int ret = StackTop(ps);
- printf("%d ", ret);
- StackPop(ps);
- }
- printf("\n");
- StackDestory(ps);
- }
-
- int main()
- {
- Test1();
- return 0;
- }

队列:只允许在一端插入数据,而在另一端删除数据的线性结构 (Frist In Frist Out)
队头:删除数据的一端
队尾:插入数据的一端
常见队列:
使用单链表实现的队列
Queue.h : 功能与类型的声明
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<stdbool.h>
- #include<assert.h>
-
- typedef int QDataType;
-
- // 使用单链表实现队列
- typedef struct QueueNode
- {
- struct QueueNode* next;
- QDataType data;
- }QNode;
-
- typedef struct Queue
- {
- QNode* head; // 队头
- QNode* tail; // 队尾
- }Queue;
-
- void QueueInit(Queue* pq); // 初始化
- void QueueDestory(Queue* pq); // 销毁队列
- void QueuePush(Queue* pq, QDataType x); // 入队列
- void QueuePop(Queue* pq); // 出队列
- QDataType QueueFront(Queue* pq); // 取队头的元素
- QDataType QueueBack(Queue* pq); // 取队尾的元素
- bool QueueEmpty(Queue* pq); // 判断队列是否为空
- int QueueSize(Queue* pq); // 计算队列中的有效元素

Queue.c : 功能实现
- #include "Queue.h"
-
- // 初始化
- void QueueInit(Queue* pq)
- {
- assert(pq);
- pq->head = pq->tail = NULL;
- }
-
- // 入队列
- void QueuePush(Queue* pq, QDataType x)
- {
- assert(pq);
- QNode* newnode = (QNode*)malloc(sizeof(QNode));
- if (newnode == NULL)
- {
- perror("QueuePush::malloc\n");
- exit(-1);
- }
- newnode->data = x;
- newnode->next = NULL;
-
- if (pq->tail == NULL)
- {
- pq->head = pq->tail = newnode;
- }
- else
- {
- pq->tail->next = newnode;
- pq->tail = newnode;
- }
- }
-
- // 出队列
- void QueuePop(Queue* pq)
- {
- assert(pq);
- // 只剩一个节点
- if (pq->head->next == NULL)
- {
- free(pq->head);
- pq->head = pq->tail = NULL; // 避免tail成为野指针 (指针的指向是不确定的)
- }
- else
- {
- // 多个节点
- QNode* next = pq->head->next;
- free(pq->head);
- pq->head = next;
- }
- }
-
- // 取队头的元素
- QDataType QueueFront(Queue* pq)
- {
- assert(pq);
- assert(!QueueEmpty(pq));
-
- return pq->head->data;
- }
-
- // 取队尾的元素
- QDataType QueueBack(Queue* pq)
- {
- assert(pq);
- assert(!QueueEmpty(pq));
-
- return pq->tail->data;
- }
-
- // 判断队列是否为空
- bool QueueEmpty(Queue* pq)
- {
- assert(pq);
- //if (pq->head == NULL)
- // return true;
-
- //return false;
- return pq->head == NULL;
- }
-
- // 计算队列中的有效元素
- int QueueSize(Queue* pq)
- {
- assert(pq);
- QNode* cur = pq->head;
- int size = 0;
- while (cur)
- {
- ++size;
- cur = cur->next;
- }
- return size;
- }
-
- // 销毁队列 - 即将队列都删空
- void QueueDestory(Queue* pq)
- {
- assert(pq);
- QNode* cur = pq->head;
- while (cur)
- {
- QNode* next = cur->next;
- free(cur);
- cur = next;
- }
- pq->head = pq->tail = NULL;
- }

New.c : 功能测试
- #include "Queue.h"
-
- void Test1()
- {
- Queue q;
- Queue* pq = &q;
- QueueInit(pq);
- QueuePush(pq, 1);
- QueuePush(pq, 2);
- QueuePush(pq, 3);
- QueuePush(pq, 4);
- QueuePush(pq, 5);
- int size = 0;
- size = QueueSize(pq);
- printf("%d:\n", size);
-
- while (!QueueEmpty(pq))
- {
- int ret = QueueFront(pq);
- printf("%d ", ret);
- QueuePop(pq);
- }
- printf("\n");
- QueueDestory(pq);
- }
-
- int main()
- {
- Test1();
- return 0;
- }

最后,我们来进行总结一下,今天的博客主要介绍了数据结构中的线性结构及它们的实现(C语言),如顺序表、链表、栈、队列;熟练掌握各种数据结构以及它们的实现,我们软件开发者在进阶过程中必须要攀登的一座“大山”!好啦,希望今天的博客能够对你有所帮助,我们山顶见!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。