线性表
1.线性表是一种数据内部的逻辑关系,与存储形式无关
2.线性表既可以采用连续的顺序存储(数组),也可以采用离散的链式存储(链表)
3.顺序表和链表都称为线性表
链表与顺序表差异
既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表。
1.顺序表
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef int dataType;//给int起别名dataType
// 定义顺序表管理结构体,名字为sequeList
typedef struct sequeList
{
int cap; // 顺序表总大小
int last; // 顺序表元素下标
dataType *data; // 指向顺序表的首元素地址
}sequeList;
// 初始化顺序表
sequeList *init_seque(int cap)
{
if(cap <= 0)
return NULL;
// 给顺序表管理结构体分配空间
sequeList *head = malloc(sizeof(sequeList));
if(head == NULL)
return NULL;
head->cap = cap;
head->last = -1;
head->data = calloc(cap,sizeof(dataType));
if(head->data == NULL)
return NULL;
return head;
}
// 判断表是否满
bool isFull(sequeList *head)
{
if(head->cap == head->last+1)
return true;
return false;
}
// 判断表为空
bool isEmpty(sequeList *head)
{
if(head->last == -1)
return true;
return false;
}
// 插入数据
bool insert(sequeList *head, dataType data)
{
if(head == NULL)
return false;
// 判断数据是否已满
if(isFull(head))
return false;
head->data[++head->last] = data;
return true;
}
void maopao(sequeList *head)
{
for (int i=0;i< head->last;i++)
{
for(int j=0;j< head->last-i;j++)
{
if(head->data[j]>head->data[j+1])
{
int temp=head->data[j];
head->data[j]=head->data[j+1];
head->data[j+1]=temp;
}
}
}
}
sequeList *removeData(sequeList *head, dataType data)
{
if(isEmpty(head))
return NULL;
// 找需要删除的数据下标
int i = 0;
for(;i <= head->last; i++)
{
if(head->data[i] == data)
{
break;
}
}
// 后面的进行覆盖
for(int j = i; j < head->last; j++)
{
head->data[j] = head->data[j+1];
}
head->last--;
return head;
}
// 显示插入的数据
void showList(sequeList *head)
{
for(int i = 0;i < head->last+1; i++)
{
printf("%d\t",head->data[i]);
}
}
// 销毁顺序表
void deStory(sequeList *head)
{
free(head->data);
head->data = NULL;
free(head);
head = NULL;
}
int main(int argc, char const *argv[])
{
// 初始化表
sequeList *head = init_seque(10);
if(head == NULL)
{
printf("init failed\n");
return -1;
}
dataType data,a;
printf("输入数据到负数结束:\n");
while(1)
{
scanf("%d",&data);
if(data<0)
{
a=-data;
break;
}
// 将输入插入到表
insert(head,data);
}
removeData(head,a);
maopao(head);
showList(head);
// 销毁顺序表
deStory(head);
return 0;
}
1.优点
不需要多余的信息来记录数据的关系,存储密度高
所有数据顺序存储在一片连续的内存中,支持立即访问任意一个随机数 据,比如上述顺序表中第i个节点是s->data[i]
2.缺点
插入、删除时需要保持数据的物理位置反映其逻辑关系,需要成片移动数据
当数据节点较多时,需要一整片较大的连续内存空间
当数据节点数量变化剧烈时,内存的释放和分配不灵活
2.链表
链表的增删改和销毁
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef int dataType;
// 数据节点
struct node
{
dataType data;
struct node *next;
};
// 头节点,管理结构体
struct headNode
{
struct node *first; // 指向首节点
struct node *tail; // 指向尾节点
int nodeNumber; // 链表节点个数
};
struct headNode *init_headNode(void)
{
struct headNode *head = malloc(sizeof(struct headNode));
if(head == NULL)
return NULL;
head->first = NULL;
head->tail = NULL;
head->nodeNumber = 0;
return head;
}
// 创建新节点
struct node *create_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
// 创建带头节点的单向链表
struct headNode* create_list(void)
{
// 初始化管理结构体
struct headNode *head = init_headNode();
if(head == NULL)
{
printf("init head node failed\n");
return NULL;
}
while(1)
{
dataType data;
if(scanf("%d",&data) == 0)// 退出
{
while(getchar()!='\n');
break;
}
// 创建新节点
struct node *pnew = create_newNode(data);
// 从无到有
if(head->first == NULL)
{
head->first = pnew;
head->tail = pnew;
}
else // 从少到多
{
// 头插法
// pnew->next=head->first;
// head->first=pnew;
// 尾插法
head->tail->next=pnew;
head->tail=pnew;
}
head->nodeNumber++;
}
return head;
}
//更新节点
struct headNode* updata(struct headNode *head,dataType data,dataType newdata)
{
//找节点
struct node *p=head->first;
while(p)
{
if(p->data==data)
{
p->data=newdata;
break;
}
else
{
p=p->next;
}
}
if(p==NULL)
{
printf("没找到要更新的数据\n");
}
return head;
}
//删除节点
struct headNode* delete(struct headNode *head,dataType data)
{
// 找节点
struct node *p = head->first;
struct node *pre=NULL;
while (p)
{
if(p->data == data)
{
break;
}
else // 继续找
{
pre=p;
p = p->next;
}
}
if(p == NULL)
{
printf("没有需要删除的数据\n");
}
else if(head->first->data==p->data)
{
head->first=p->next;
head->nodeNumber--;
free(p);
p=NULL;
}
else//在中间
{
pre->next=p->next;
head->nodeNumber--;
free(p);
p=NULL;
}
return head;
}
//添加节点
struct headNode *add_node(struct headNode *head,dataType data,dataType newdata)
{
//创建新节点
struct node *pnew=create_newNode(newdata);
if(pnew==NULL)
return NULL;
struct node *p=head->first;
struct node *pre=NULL;
//找插入位置
while(p)
{
if (p->data==data)
break;
else
{
pre=p;
p=p->next;
}
}
//如果没有找到
if(p==NULL)
head->tail=pnew;
//如果在头部
else if(head->first->data==p->data)
{
pnew->next=head->first;
head->first=pnew;
}
else//在其他位置
{
pnew->next=p;
pre->next=pnew;
}
head->nodeNumber++;
return head;
}
//冒泡排序
struct headNode * bubble(struct headNode *head)
{
for(int i = 0; i < head->nodeNumber-1; i++)
{
struct node *p=head->first;
// 将每一遍的数据比较后进行交换
for(int j = 0; j < head->nodeNumber-i-1; j++)
{
if((p->data) > (p->next->data))
{
int temp = p->data;
p->data =p->next->data;
p->next->data = temp;
}
p=p->next;
}
}
return head;
}
//反转链表
struct headNode * reverse_list(struct headNode *head)
{
// struct node *prev = NULL;
// struct node *curr = head->first;
// struct node *next = NULL;
// while (curr != NULL)
// {
// next = curr->next;
// curr->next = prev;
// prev = curr;
// curr = next;
// }
// head->first = prev;
// return head;
//拆合
struct node *p=head->first;
struct node *pnew=NULL;
head->first=NULL;
head->tail=NULL;
while(p)
{
//拆
pnew=p;
p=p->next;
pnew->next=NULL;
//合
if (head->first==NULL)
{
head->first=pnew;
head->tail=pnew;
}
else
{
pnew->next=head->first;
head->first=pnew;
}
}
return head;
}
//合并
struct headNode *merge_tow_list(struct headNode *head1,struct headNode *head2)
{
struct node *pA= head1->first;
struct node *pB= head2->first;
struct headNode *head=malloc(sizeof(struct headNode));
struct node *pnew =head->first;
head->first=NULL;
head->tail=NULL;
head->nodeNumber=head1->nodeNumber+head2->nodeNumber;
while(pA&&pB)
{
if(pA->data<pB->data)
{
pnew=pA;
pA=pA->next;
pnew->next=NULL;
}
else
{
pnew=pB;
pB=pB->next;
pnew->next=NULL;
}
if(head->first==NULL)
{
head->first=pnew;
head->tail=pnew;
}
else
{
head->tail->next=pnew;
head->tail=pnew;
}
}
if(pA!=NULL)
{
head->tail->next=pA;
head->tail=head1->tail;
}
else
{
head->tail->next=pB;
head->tail=head2->tail;
}
//释放
head1->first=NULL;
head1->tail=NULL;
head2->first=NULL;
head2->tail=NULL;
free(head1);
free(head2);
return head;
}
// 判断链表是否为空
bool isEmpty(struct headNode *head)
{
if(head->nodeNumber == 0)
return true;
return false;
}
// 显示链表
void show_list(struct headNode *head)
{
if( isEmpty(head))
return;
for(struct node *p = head->first; p != NULL; p =p->next)
{
printf("%d\t",p->data);
}
printf("\n");
printf("链表已有%d个节点\n",head->nodeNumber);
}
// 销毁链表
struct headNode * distory_list(struct headNode *head)
{
if(isEmpty(head))
return false;
// 逐一删除节点
struct node *p = NULL;
for(struct node *tmp = head->first;tmp != NULL; tmp = p)
{
p = tmp->next;
free(tmp);
head->nodeNumber--;
}
return head;
}
int main(int argc, char const *argv[])
{
// 创建链表
// struct headNode *head1= create_list();
// if(head1==NULL)
// return -1;
// struct headNode *head2= create_list();
// if(head2==NULL)
// return -1;
struct headNode *head= create_list();
if(head==NULL)
return -1;
//更新节点
// head=updata(head,5,8);
// show_list(head);
//删除节点
// head=delete(head,1);
// show_list(head);
//添加节点
head=add_node(head,8,6);
show_list(head);
//排序
// head=bubble(head);
// show_list(head);
// 销毁链表
// distory_list(head);
//反转链表
// head=reverse_list(head);
// show_list(head);
//合并两条有序链表
// struct headNode *head=merge_tow_list(head1,head2);
// show_list(head);
return 0;
}
3.栈(先进后出)
顺序栈
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int dataType;
// 定义顺序栈管理结构体
typedef struct
{
dataType *data; // 指向顺序栈的首地址
int size; // 顺序栈容量
int top; // 栈顶
}seqStack;
// 初始化顺序栈
seqStack *init_stack(int size)
{
seqStack *s = malloc(sizeof(seqStack));
if(s == NULL)
return NULL;
s->data = calloc(size,sizeof(dataType));
if(s->data == NULL)
return NULL;
s->size = size;
s->top = -1;
return s;
}
// 判断栈满
bool is_full(seqStack *s)
{
return s->top == s->size-1;
}
// 判断栈为空
bool isEmpty(seqStack *s)
{
return s->top == -1;
}
// 入栈
// bool push(seqStack *s,dataType data)
// {
// // 判断是否栈满
// if(is_full(s))
// return false;
// s->data[++s->top] = data;
// return true;
// }
void push(seqStack *s,dataType data)
{
if (is_full(s))
{
printf("Stack is full.\n");
return;
}
s->data[++s->top] = data;
}
// 取栈顶,不出栈
bool top(seqStack *s, dataType *data)
{
if(isEmpty(s))
return false;
// 取栈顶元素
*data = s->data[s->top];
return true;
}
// 出栈
// bool pop(seqStack *s, dataType *data)
// {
// if(!top(s,data))
// {
// return false;
// }
// s->top--;
// return true;
// }
int pop(seqStack *s)
{
if (isEmpty(s))
{
printf("Stack is empty.\n");
return -1;
}
return s->data[s->top--];
}
//打印栈
void printStack (seqStack *s)
{
if (isEmpty(s))
{
printf("Stack is empty.\n");
return;
}
printf("Stack: ");
for(int i=0;i<=s->top;i++)
{
printf("%d",s->data[i]);
}
printf("\n");
}
//输入数字或字母时,依次入栈,出栈
void stack(seqStack *s)
{
char input;
dataType data;
while(1)
{
printf("请输入数字或字母:");
scanf("%c",&input);
getchar();
if(input >= '0' && input <= '9')
{
data=input-'0';
push(s, data);
}
else if(input >= 'a' && input <= 'z')
{
data=pop(s);
}
else
{
printf("输入错误\n");
continue;
}
printStack (s);
}
}
//十进制转八进制
void list(seqStack *s)
{
int input,pro,a;
scanf("%d",&input);
getchar();
do
{
a=input%8;
push(s, a);
input=input/8;
} while (input!=0);
printStack(s);
}
int main(int argc, char const *argv[])
{
seqStack *s = init_stack(10);
if(s == NULL)
{
printf("init stack failed\n");
return -1;
}
// 入栈
// push(s,1);
// push(s,2);
// push(s,3);
// dataType data;
// // 弹栈
// while (s->top != -1)
// {
// pop(s,&data);
// printf("%d\t",data);
// }
// printf("\n");
//输入数字或字母时,依次入栈,出栈
// stack(s);
list(s);
return 0;
}
链式栈
//链式栈
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
typedef int dataType;
// 数据节点
typedef struct node
{
dataType data;
struct node *next; // 指向下一个node节点
}node;
// 链式栈管理结构体
typedef struct
{
node *top; // 栈顶
int size; // 节点数
}linkStack;
// 初始化链式栈
linkStack *init_linkStack(void)
{
linkStack *ls = malloc(sizeof(linkStack));
if(ls == NULL)
return NULL;
ls->top = NULL;
ls->size = 0;
return ls;
}
// 创建新节点
node *create_node(dataType data)
{
node *pnew = malloc(sizeof(node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
// 入栈
bool push(linkStack *ls, dataType data)
{
// 创建节点
node *pnew = create_node(data);
if(pnew == NULL)
return false;
// 头插
pnew->next = ls->top;
ls->top = pnew;
ls->size++;
return true;
}
// 判断栈是否为空
bool is_empty(linkStack *ls)
{
return ls->size == 0;
}
// 获取栈顶节点元素
node *top(linkStack *ls)
{
if(is_empty(ls))
return NULL;
return ls->top;
}
// 弹栈
node *pop(linkStack *ls)
{
node *p = top(ls);
if(p == NULL)
return NULL;
ls->top = p->next;
p->next = NULL;
ls->size--;
return p;
}
int main(int argc, char const *argv[])
{
// 初始化链式栈
linkStack *ls = init_linkStack();
if(ls == NULL)
{
printf("init linkstack failed\n");
return -1;
}
// push(ls,1);
// push(ls,2);
// push(ls,3);
// while(ls->size != 0)
// {
// node *p = pop(ls);
// if(p == NULL)
// {
// printf("pop failed\n");
// return -1;
// }
// printf("%d\n",p->data);
// }
// printf("栈为空\n");
int data;
scanf("%d",&data);
while(data>0)
{
push(ls,data%8);
data/=8;
}
printf("0");
while(1)
{
if(is_empty(ls))
break;
node *p=pop(ls);
printf("%d",p->data);
}
printf("\n");
return 0;
}
4.队列(先进先出)
顺序循环队列
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int dataType;
typedef struct
{
dataType *data;
int cap;
int front;
int rear;
}seqQueue;
//初始化队列
seqQueue *init_seqQueue(int size)
{
seqQueue *sq=malloc(sizeof(seqQueue));
if(sq==NULL)
return NULL;
sq->data=calloc(size,sizeof(dataType));
sq->cap=size;
sq->front=sq->rear=0;
return sq;
}
//判断队列是否为满
bool is_full(seqQueue *sq)
{
return (sq->rear+1)%sq->cap==sq->front;
}
//队列为空
bool is_empty(seqQueue *sq)
{
return sq->front==sq->rear;
}
//入队
bool enQuque(seqQueue *sq,dataType data)
{
if(is_full(sq))
{
return false;
}
//尾入
sq->data[sq->rear]=data;
sq->rear=(sq->rear+1)%sq->cap;//尾巴的下标加一,下一次从此下标入队;
return true;
}
//出队
bool outQueue(seqQueue *sq,dataType *data)
{
if(is_empty(sq))
return false;
*data=sq->data[sq->front];
sq->front=(sq->front+1)%sq->cap;
return true;
}
int main(int argc, char const *argv[])
{
//初始化队列
seqQueue *sq=init_seqQueue(5);
if(sq==NULL)
{
printf("创建队列为空\n");
return -1;
}
for (int i=0;i<4;i++)
{
enQuque(sq,i);
}
dataType data;
while(1)
{
if(!outQueue(sq,&data))
{
printf("队列为空\n");
break;
}
printf("%d\n",data);
}
return 0;
}
链式队列
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int dataType;
// 数据节点
struct node
{
dataType data;
struct node *next;
}node;
// 管理结构体
typedef struct linkQueue
{
struct node *fron; // 头节点
struct node *rear; // 尾节点
int size; // 节点数
}linkQueue;
// 初始化管理结构体
linkQueue *init_linkQueue()
{
linkQueue *lq = malloc(sizeof(linkQueue));
if(lq == NULL)
return NULL;
lq->fron = NULL;
lq->rear = NULL;
lq->size = 0;
return lq;
}
// 队列为空
bool is_empty(linkQueue *lq)
{
return lq->size == 0;
}
// 创建新节点
struct node *create_node(dataType data)
{
struct node *pnew = malloc(sizeof(node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
// 入队
bool enQueue(linkQueue *lq, dataType data)
{
// 创建新节点
struct node *pnew = create_node(data);
if(pnew == NULL)
return false;
// 从无到有
if(is_empty(lq))
{
lq->fron = lq->rear = pnew;
}
else
{
lq->rear->next = pnew;
lq->rear = pnew;
}
lq->size++;
return true;
}
// 取队头元素,不出队
bool front(linkQueue *lq, dataType *data)
{
if(is_empty(lq))
return false;
*data = lq->rear->data;
return true;
}
// 出队
bool outQueue(linkQueue *lq, dataType *data)
{
if(!front(lq,data))
{
return false;
}
// 将头节点剔除
// 如果链表只有一个节点
if(lq->size == 1)
{
free(lq->fron);
lq->fron = NULL;
lq->rear = NULL;
}
else
{
struct node *tmp = lq->fron;
lq->fron = tmp->next;
tmp->next = NULL;
free(tmp);
}
lq->size--;
return true;
}
//显示
void show(linkQueue *lq)
{
struct node *pnew=lq->fron;
while(pnew!=NULL)
{
printf("%d\t",pnew->data);
pnew=pnew->next;
}
printf("\n");
}
int main(int argc, char const *argv[])
{
//初始化管理结构体
linkQueue *lq=init_linkQueue();
if (lq==NULL)
{
printf("init queue failed\n");
return -1;
}
while(1)
{
dataType data=-1;
if(scanf("%d",&data)==1)
{
if(!enQueue(lq,data))
{
printf("队列满\n");
break;
}
}
else
{
while(getchar() != '\n');
dataType data = -1;
if(!outQueue(lq,&data))
{
printf("队列空\n");
break;
}
}
show(lq);
}
return 0;
}
lq->size == 1)
{
free(lq->fron);
lq->fron = NULL;
lq->rear = NULL;
}
else
{
struct node *tmp = lq->fron;
lq->fron = tmp->next;
tmp->next = NULL;
free(tmp);
}
lq->size–;
return true;
}
//显示
void show(linkQueue *lq)
{
struct node *pnew=lq->fron;
while(pnew!=NULL)
{
printf(“%d\t”,pnew->data);
pnew=pnew->next;
}
printf(“\n”);
}
int main(int argc, char const *argv[])
{
//初始化管理结构体
linkQueue *lq=init_linkQueue();
if (lq==NULL)
{
printf(“init queue failed\n”);
return -1;
}
while(1)
{
dataType data=-1;
if(scanf("%d",&data)==1)
{
if(!enQueue(lq,data))
{
printf("队列满\n");
break;
}
}
else
{
while(getchar() != '\n');
dataType data = -1;
if(!outQueue(lq,&data))
{
printf("队列空\n");
break;
}
}
show(lq);
}
return 0;
}