双向链表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/89490360
单向链表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/89472595
首先我们先介绍一下线性表,线性表是N个有着相同特性的数据元素的有限链表。线性表是一种实际中广泛使用的数据结构,常见的线性结构有:顺序表,链表,栈,队列,字符串…。
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表
顺序表的概念:它是一段物理地址连续的储存空间依次储存数据元素的线性结构,一般情况下,使用的是数组储存,在数组中,完成数据的增删查改。
首先,先给大家一些接口,如果能力强的同学,可以自己练习一下。
#ifndef __SEQLIST_H__
#define __SEQLIST_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<assert.h>
//顺序表的静态储存;
//#define N 100; //这一部分,我们太不需要,因为动态符合我们所需要的。
//typedef int SLDataType;
//
//typedef struct SeqList
//{
// SLDataType array[N];
// size_t size;
//}SeqList;
//顺序表的动态储存;
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* _array;
size_t _size;
size_t _capacity;
}SeqList;
void SeqListInit(SeqList* ps,size_t _capacity);
void SeqListDestory(SeqList* ps);
void CheckCapacity(SeqList* ps);
void SeqListPushBank(SeqList* ps,SLDataType x);
void SeqListPopBank(SeqList* ps);
void SeqListPushFort(SeqList* ps,SLDataType x);
void SeqListPopFort(SeqList* ps);
void SeqListPrint(SeqList* ps);
int SeqListFind(SeqList* ps, SLDataType x);
void SeqListInsert(SeqList* ps ,size_t pos , SLDataType x);
void SeqListErase(SeqList* ps, size_t pos);
void SeqListBubblesort(SeqList* ps, SLDataType x);
int SeqListBinaryFind(SeqList* ps, SLDataType x);
void SeqListRemoveAll(SeqList* ps, SLDataType x);
#endif //__SEQLIST_H__
下来就是我们的完整代码了,根据上面的接口,我们测试函数与主函数放在一起了,如果需要分开的话,请自行把分开。
#include "SeqList.h"
void SeqListInit(SeqList* ps,size_t capacity) //初始化
{
assert(ps);
ps->_array = (SLDataType*)malloc(sizeof(SLDataType)*capacity);
ps->_capacity = capacity;
ps->_size = 0;
}
void SeqListDestory(SeqList* ps) //释放
{
assert(ps);
if(ps->_array)
{
free(ps->_array );
ps->_array = NULL;
ps->_capacity = ps->_size = 0;
}
}
void CheckCapacity(SeqList* ps) //检查容量
{
assert(ps);
if(ps->_size == ps->_capacity ) //等号没有写好;
{
ps->_capacity *= 2;
ps->_array =realloc(ps->_array , ps->_capacity * sizeof(SLDataType));
assert(ps->_array);
}
}
void SeqListPushBank(SeqList* ps,SLDataType x) //尾插
{
assert(ps);
CheckCapacity(ps);
ps->_array[ps->_size ] = x;
ps->_size++;
}
void SeqListPopBank(SeqList* ps) //尾删
{
assert(ps && ps->_array);
ps->_size--;
}
void SeqListPushFort(SeqList* ps,SLDataType x) //头插
{
int end = ps->_size-1;
assert(ps);
CheckCapacity(ps);
while(end >= 0)
{
ps->_array[end+1] = ps->_array[end];
--end;
}
ps->_array[0]= x;
ps->_size++;
}
void SeqListPopFort(SeqList* ps) //头删
{
int left = 0;
int right = ps->_size - 1;
assert(ps);
while(left < right)
{
ps->_array[left] = ps->_array[left + 1];
left++;
}
ps->_size--;
}
int SeqListFind(SeqList* ps, SLDataType x) //查找
{
int i = 0;
assert(ps);
for(i = 0; i< ps->_size;i++)
{
if(x == ps->_array[i])
{
return i;
}
}
return -1;
}
void SeqListInsert(SeqList* ps ,size_t pos , SLDataType x) //在当前位置插入
{
int end = ps->_size -1;
assert(ps && pos < ps->_size );
while(end >= 0)
{
ps->_array[end + 1] = ps->_array[end];
--end;
}
ps->_array[pos] = x;
ps->_size++;
}
void SeqListErase(SeqList* ps, size_t pos) //在当前位置删除
{
int i = 0;
assert(ps);
while(pos < ps->_size) //这里不是变量加一,而是找的那个位置加一;
{
ps->_array[pos] = ps->_array[pos + 1];
pos++;
}
ps->_size--;
}
void SeqListBubblesort(SeqList* ps) //冒泡排序
{
int i = 0 ;
int end = 0;
end = ps->_size-1 ;
assert(ps);
while(end >= 0)
{
for(i = 0 ;i < end ; i++)
{
if(ps->_array[i] > ps->_array[i + 1])
{
SLDataType tmp = ps->_array[i];
ps->_array[i] = ps->_array[i + 1];
ps->_array[i+1] = tmp;
}
}
end--;
}
}
int SeqListBinaryFind(SeqList* ps, SLDataType x) //二分查找(有一点小问题,找到了,请告诉我)
{
int start = 0;
int end = ps ->_size;
int mid = 0;
while(start < end)
{
mid = (start + end)/2;
if(ps ->_array[mid] == x)
{
return mid;
}
else if(ps ->_array[mid] > x)
{
end = mid + 1;
}
else
{
start = mid + 1;
}
}
return -1;
}
void SeqListRemoveAll(SeqList* ps, SLDataType x) //删除当前以后的全部位置
{
int i =0 ;
assert(ps);
for(i =0 ; i< ps->_size ;i++)
{
if(ps->_array[i] == x)
{
SeqListErase(ps,x);
i--;
}
}
}
void SeqListPrint(SeqList* ps)
{
int i = 0;
for(i = 0; i < ps->_size ; i++)
{
printf("%d ",ps->_array[i]);
}
printf("\n");
}
int main()
{
SeqList s;
SeqListInit(&s,10);
SeqListPushBank(&s,1);
SeqListPushBank(&s,3);
SeqListPushBank(&s,2);
SeqListPushBank(&s,4);
SeqListPushBank(&s,6);
SeqListPushBank(&s,8);
SeqListPushBank(&s,7);
SeqListPrint(&s);
//几个函数接口的实现,调用函数。
SeqListBubblesort(&s);
SeqListPrint(&s);
//printf("%d\n",SeqListBinaryFind(&s,7));
SeqListRemoveAll(&s,4);
SeqListPrint(&s);
//前几个接口的实现,调用函数。
/*SeqListPopBank(&s);
SeqListPrint(&s);
SeqListPushFort(&s,0);
SeqListPrint(&s);
SeqListPopFort(&s);
SeqListPrint(&s);*/
/* printf("%d\n",SeqListFind(&s,2));
SeqListInsert(&s , 0 , 0);
SeqListPrint(&s);
SeqListErase(&s,0);
SeqListPrint(&s);*/
SeqListDestory(&s);
return 0;
}
顺序表的问题及思考
问题:
1. 中间/头部的插入删除,时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,
我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
思考:
如何解决以上问题呢?下面给出了链表的结构来看看。我会把链接发在下面的
双向链表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/89490360
单向链表的实现代码及接口:https://blog.csdn.net/dpfxaca6/article/details/89472595
如果还有什么地方,不足的话,请大佬下面留言,谢谢。