基本数据结构
1.线性表
在数据结构中,线性表是最常见也是使用最频繁的基本数据结构,它可以通过数组实现或者链表实现。
/通过数组实现
#include<stdio.h>
#include<stdbool.h>
#define MAXSIZE 5
#define ElementType int
typedef struct LNode* List;
struct LNode
{
ElementType Data[MAXSIZE];
int last;
};
//make a empty arraylist
List makeEmpty(){
List ptrl;
ptrl = (List)malloc(sizeof(struct LNode));
ptrl->last = 0;
return ptrl;
}
//find element by value
int findInValue(ElementType value,List ptrl){
int i = 0;
while(i <= ptrl->last){
if(value == ptrl->Data[i++]){
return i-1;
}
}
return -1;
}
//find element by index
ElementType findInIndex(int index,List ptrl){
if(index > ptrl->last)
{
return -1;
}
else
{
return ptrl->Data[index];
}
}
//check the arraylist is full
bool isFull(List ptrl){
if(ptrl->last == MAXSIZE){
return true;
}
else{
return false;
}
}
//insert by index
void insert(ElementType value,int index,List ptrl)
{
if(isFull(ptrl)){
printf(“warning!!!”);
return;
}
else if(index < 0 || index > ptrl->last){
printf(“warning!!!”);
return;
}
else{
for(int i = ptrl->last;i > index;i–)
{
ptrl->Data[i] = ptrl->Data[i-1];
}
ptrl->Data[index] = value;
ptrl->last++;
}
}
//delete element by index
void delete(int index,List ptrl){
if(isEmptry(ptrl)){
printf(“warning!!!”);
return;
}
else if(index < 0 || index >= MAXSIZE)
{
printf(“warning!!!”);
return;
}
else{
for(int i = index;i < ptrl->last; i++)
{
ptrl->Data[i] = ptrl->Data[i+1];
}
ptrl->last–;
}
}
//printflist
void printList(List ptrl){
for(int i = 0;ilast;i++)
{
printf("%d",ptrl->Data[i]);
}
printf("\n");
}
//test code
int main(void){
List L = makeEmpty();
for(int i=0;i<6;i++)
{
insert(i,0,L);
printList(L);
}
printf(“index of %d is %d\n”, 3, findInIndex(3,L));
printf(“the %d in %d\n”, 1, findInValue(1,L));
for (int i = 1; i < 6; i++) {
delete(0, L);
printList(L);
}
//implemented by linklist
#include<stdio.h>
#include<stdbool.h>
#include “malloc.h”
typedef struct LNode* List;
#define ElementType int
struct LNode
{
ElementType Data;
List Next;
};
//get link list length,the empty table has a header,the default length is 0
int length(List ptrl){
List temp = ptrl;
int len = 0;
while(temp->Next){
temp = temp->Next;
len++;
}
return len;
}
//make an empty linked list,generate an empty header(length is 1)
List makeEmpty(){
List ptrl;
ptrl = (List)malloc(sizeof(struct LNode));
ptrl->Next = NULL;
return ptrl;
}
//check the linklist is empty
bool isEmpty(List ptrl){
if(length(ptrl) == 0){
return true;
}
else{
return false;
}
}
//find element by index,the index of the header is 0,(index>=0)
List findInIndex(int index,List ptrl){
int i = 0;
List temp = ptrl;
while(temp != NULL && i < index){
temp = temp->Next;
i++;
}
if(i == index){
return temp;
}
else{
return NULL;
}
}
//find element by value
List findInValue(ElementType value,List ptrl){
List temp = ptrl;
while(temp)
{
if(temp->Data == value){
break;
}
temp = temp->Next;
}
return temp;
}
//Insert element at specified position(1-the last)
List insert(ElementType value,int index,List ptrl){
List temp = findInIndex(index-1,ptrl);
if(temp == NULL){
printf(“warning:the index is invalid.”);
return NULL;
}
else{
List newLNode = (List)malloc(sizeof(struct LNode));
newLNode->Data = value;
if(temp->Next == NULL){
temp->Next = newNode;
newLNode->Next = NULL;
}
else{
newLNode->Next = temp->Next;
temp->next = newLNode;
}
return ptrl;
}
}
//printf list
void printList(List ptrl){
if(isEmpty(ptrl)){
return;
}
List temp = ptrl->Next;
while(temp){
printf("%d",temp->Data);
temp = temp->Next;
}
printf("\n");
}
//Delete the node at the specified position(0<index<last)
List delete(int index,List ptrl){
if(isEmpty(ptrl)){
printf(“the linked list has been empty.”);
return ptrl;
}
List temp = findInIndex(index - 1,ptrl);
List tempNext = temp->Next;
if(temp->Next->Next != NULL){
temp->Next = temp->Next->Next;
}
else{
temp->Next = NULL;
}
free(tempNext);
return ptrl;
}
int main(void){
List L = makeEmpty();
L = insert(3,1,L);
printfList(L);
L = insert(5, 1, L);
printList(L);
L = insert(1, 1, L);
printList(L);
L = delete(2, L);
printList(L);
printf("%d", length(L));
}
在通过链表实现线性表时,常见的做法是建立一个空表头不存储任何数据,当表头的下一个指向为空时,线性表为空,这样做虽然会在内存上有一点的浪费,但操作起来相对更方便。
堆栈
对于一个堆栈,它特有的性质是先进后出,后进先出,就像把盘子叠在一起,最后放在上面的盘子会被更早用到。同样可以用数组实现或是链实现。
#include<stdio.h>
#include<stdbool.h>
#include “malloc.h”
typedef struct SNode *Stack;
#define MAXSIZE 10
#define ElementType int
struct SNode
{
ElementType Data[MAXSIZE];
int top;
};
//make a empty stack
Stack makeEmpty(){
Stack S = (Stack)malloc(sizeof(struct SNode));
S->top = 0;
}
//check is empty
bool isEmpty(Stack ptrs)
{
if(ptrs->top == 0){
return true;
}
return false;
}
//check is full
bool isFull(Stack ptrs){
if(ptrs->top == MAXSIZE){
return true;
}
return false;
}
//push element
void push(ElementType value,Stack ptrs){
if(isFull(ptrs)){
printf(“the stack has been full.”);
return;
}
ptrs->Data[ptrs->top++] = value;
}
//pop
ElementType pop(Stack ptrs){
if(isEmpty(ptrs))
{
printf(“the stack has been empty.”);
return;
}
return ptrs->Data[–ptrs->top];
}
int main(){
Stack S = makeEmpty();
for(int i=0;i<6;i++){
push(i,S);
}
while(!isEmpty(S)){
printf("%d",pop(S));
}
return 0;
}
对于用链表构造一个堆栈,那么栈顶应该是在链表的尾部还是头部?答案是都可以,栈顶在头顶的话,入栈时,因为我们有空头节点的原因,直接建立一个新节点保存元素,将新节点的Next指向空头结点的Next,在把空头结点的Next指向新结点。出栈用一个临时指针(temp)指向空头结点的Next,在将空头结点的Next指向temp指向结点的Next,这样就将需要抛出的元素从链表中取出,保存元素值,释放掉该结点(free),返回要抛出的元素;栈顶在尾部的话,入栈时,因为我们有空头节点的原因,无需考虑链表空和不空状态下的不同操作,直接用指针遍历到最后一个元素,建立一个新起点保存的元素,然后把它接在列表的末尾。出栈时,我们可以遍历的方法,直到ptrs−>Next−>Next为NULL时,此时ptrs所指的正好是栈顶的第二个元素,保证了不会出现抛出后无法回去(如果直接遍历到栈顶元素会无法找到栈顶元素的上一个节点,无法将其的Next设为NULL,这将会导致错误),用一个临时指针指向ptrs−>Next(也就是栈顶元素的节点),保存元素的值,然后释放掉该节点,将ptrs指向的节点Next设为NULL,返回需要抛出元素的值。(注意:栈顶在尾部,堆栈一定要有空头节点,否则实现起来将会极其困难复杂)
虽然栈顶在头部或者尾部都可以,但还是建议栈顶设置在在头部(从算法上看在头部相比在尾部会更快)。
//The top of the stack is at the head of the list
#include<stdio.h>
#include<stdbool.h>
#include “malloc.h”
typedef struct SNode* Stack;
#define ElementType int
struct SNode
{
ElementType Data;
Stack Next;
};
//get link stack length,the empty stack has a header,the default length is 0
int length(Stack ptrs){
Stack temp = ptrs;
int len = 0;
while(temp->Next){
temp = temp->Next;
len++;
}
return len;
}
//make an empty linked Stack,generate an empty header(length is 1)
Stack makeEmpty(){
Stack ptrs;
ptrs = (Stack)malloc(sizeof(struct SNode));
ptrs->Next = NULL;
return ptrs;
}
//check the linklist is empty
bool isEmpty(Stack ptrs){
if(length(ptrs) == 0){
return true;
}
return false;
}
//push
Stack push(ElementType value,Stack ptrs){
Stack newLNode = (Stack)malloc(sizeof(struct SNode));
newLNode->Data = value;
newLNode->Next = ptrs->Next;
ptrs->Next = newNode;
return ptrs;
}
//pop
ElementType pop(Stack ptrs){
if(isEmpty(ptrs)){
printf(“the Stack has been empty.”);
return -1;
}
Stack temp = ptrs->Next;
ElementType value = temp->Data;
ptrs->Next = temp->Next;
free(temp);
return value;
}
//print Stack
void printStack(Stack ptrs){
if(isEmpty(ptrs)){
return;
}
Stack temp = ptrs->Next;
while(temp){
printf("%d",temp->Data);
temp = temp->Next;
}
printf("\n");
}
int main()
{
Stack s = makeEmpty();
for(int i=0;i<5;i++){
ElementType value;
scanf_s("%d",&value);
S = push(value,S);
}
printStack(S);
while(!isEmpty(S)){
printf("%d",pop(S));
}
return 0;
}
//The top of the stack is at the tail of the list
#include<stdio.h>
#include<stdbool.h>
#include “malloc.h”
typedef struct SNode* Stack;
#define ElementType int
struct SNode
{
ElementType Data;
Stack Next;
};
//get link stack length,the empty stack has a header,the default length is 0
int length(Stack ptrs){
Stack temp = ptrs;
int len = 0;
while(temp->Next){
temp = temp->Next;
len++;
}
return len;
}
//make an empty linked Stack,generate an empty header(length is 1)
Stack makeEmpty(){
Stack ptrs;
ptrs = (Stack)malloc(sizeof(struct SNode));
ptrs->Next = NULL;
return ptrs;
}
//check the linklist is empty
bool isEmpty(Stack ptrs){
if(length(ptrs) == 0){
return true;
}
return false;
}
//push
Stack push(ElementType value,Stack s){
Stack newLNode = (Stack)malloc(sizeof(struct SNode));
newLNode->Data = value;
newLNode->Nex = NULL;
Stack ptrs = S;
while(ptrs->Next){
ptrs = ptrs->Next;
}
ptrs->Next = newLNode;
return S;
}
//pop
ElementType pop(Stack S){
if(isEmpty(S)){
printf(“the Stack has been empty.”);
return -1;
}
Stack ptrs = S;
while(ptrs->Next->Next){
ptrs = ptrs->Next;
}
Stack temp = ptrs->Next;
ElementType value = temp->Data;
ptrs->Next = NULL;
free(temp);
return value;
}
//print Stack
void printStack(Stack ptrs){
if(isEmpty(ptrs)){
return;
}
Stack temp = ptrs->Next;
while(temp){
printf("%d",temp->Data);
temp = temp->Next;
}
printf("\n");
}
int main(){
Stack S = makeEmpty();
for(int i = 0 ;i < 2;i++){
ElementType value;
scanf_s("%d",&value);
S = push(value,S);
}
printStack(S);
while(!isEmpty(S)){
printf("%d",pop(S));
}
return 0;
}
队列
队列具有先进先出后进后出的特性。同样可以通过数组或者链表实现。
//implements by array
#include<stdio.h>
#include<stdbool.h>
#include"malloc.h"
#define ElementType int
#define MAXSIZE 10
typedef struct QNode* Queue;
struct QNode
{
ElementType Data[MAXSIZE];
int front;
int rear;
};
Queue makeempty(){
Queue Q = (Queue)malloc(sizeof(struct QNode));
Q->front = 0;
Q->rear = 0;
return Q;
}
void QueueAdd(ElementType value,Queue ptrq){
if((ptrq->rear + 1) % MAXSIZE == ptrq->front){
printf(“The queue has been full.”);
return;
}
ptrq->rear = (++ptrq->rear) % MAXSIZE;
ptrq->Data[ptrq->rear] = value;
}
ElementType QueueDelete(Queue ptrq){
if(ptrq->front == ptrq->rear){
pritf(“The queue has been empty.”);
return -1;
}
ptrq->front = (++ptrq->front) % MAXSIZE;
return ptrq->Data[ptrq->front];
}
int main(void){
Queue Q = makeempty();
for(int i = 1;i < 10;i++){
ElementType value;
scanf_s("%d",&value);
QueueAdd(value,Q);
}
QueueDelete(Q);
QueueAdd(10,Q);
return 0;
}
//implements by linklist
#include<stdio.h>
#include<stdlib.h>
#define ElementType int
typedef struct QNode* Queue;
struct QNode
{
ElementType Data;
Queue Next;
};
Queue makeEmpty(){
Queue Q = (Queue)malloc(sizeof(struct QNode));
Q->Next = NULL;
return Q;
}
void QueueAdd(ElementType value,Queue Q){
Queue temp = Q->Next;
Queue newNode = (Queue)malloc(sizeof(struct QNode));
newNode->Data = value;
newNode->Next = temp;
Q->Next = newNode;
}
ElementType QueueDelete(Queue Q){
Queue ptrq = Q;
if(!ptrq->Next){
printf("“The queue has been empty.);
return -1;
}
while(ptrq->Next->Next){
ptrq = ptrq->Next;
}
Queue temp = ptrq->Next;
ptrq->Next = NULL;
ElementType value = temp->Data;
free(temp);
return value;
}
int main(void){
Queue Q = makeEmpty();
for(int i = 1;i < 5;i++)
{
ElementType value;
scanf_s(”%d",&value);
QueueAdd(value,Q);
}
QueueDelete(Q);
QueueAdd(5,Q);
return 0;
}
两个有序链表序列的合并
#include<stdio.h>
#include<stdlib.h>
#include “malloc.h”
typedef int ElementType;
typedef struct Node* PtrToNode;
struct Node{
ElementType Data;/存储结点数据/
PtrToNode Next;/指向下一个结点的指针/
};
typedef PtrToNode List;
List Read();
void Print(List L);/空链表将输出NULL/
List Merge(List L1,List L2);
int main()
{
List L1,L2,L;
L1 = Read();
L2 = Read();
L = Merge(L1,L2);
Print(L);
Print(L1);
Print(L2);
return 0;
}
List Read(){
//申请一块空间存储1,初始的最后一位是0
List L = (List)malloc(sizeof(struct Node));
L->Next = NULL;
List ptrl = L;
//要读多少个数?
int num;
scanf_s("%d",&num);
//逐个读入,读入的同时增大最后一位的位置。
for(int i = 0;i < num;i++){
ElementType value;
scanf_s("%d",&value);
List newLNode = (List)malloc(sizeof(struct Node));
newLNode->Data = value;
newLNode->Next = NULL;
ptrl->Next = newLNode;
ptrl = ptrl->Next;
}
return L;
}
void Print(List L){
int isfirst = 1;
List ptrl = L->Next;
if(ptrl == NULL){
printf(“NULL\n”);
return;
}
else{
while(ptrl)
{
if(isfrist){
printf("%d",ptrl->Data);
isfrist = 0;
}
else{
printf("%d",ptrl->Data);
}
ptrl = ptrl->Next;
}
printf("\n");
}
return;
}
List Merge(List L1,List L2){
//存储合并后的链表
List L = (List)malloc(sizeof(struct Node));
//三个指针分别用于遍历l1和l2和l
List ptrl1 = L1->Next,ptrl2 = L2->Next;ptrl= L;
//两个链表都不空时,进行循环比较,其中任意一方空则退出
while(ptrl1 && ptrl2){
//ptrl1指向的数据比ptrl2时,将其
if(ptrl1->Data < ptrl2->Data){
ptrl1->Next = ptrl1;
ptrl1 = ptrl1->Next;
}
else{
ptrl1->Next = ptrl2;
ptrl2 = ptrl2->Next;
}
ptrl = ptrl->Next;
}
//如果链表1空了,将现在未处理的链表2接到1末尾,列表2空了同理…
if(ptrl1 == NULL){
ptrl1->Next = ptrl2;
}
if(ptrl2==NULL){
ptrl->Next = ptrl1;
}
//将l1和l2指向为null
L1->Next = NULL;
L2-Next = NULL;
//将合并后的链表返回
return L;
}