数据结构与算法

本文介绍了顺序表的逻辑结构和存储结构,包括插入、删除元素以及动态扩容的实现。同时,详细阐述了单向链表和双向链表的节点结构和插入、删除操作。还提及了栈和队列的特性以及简单的排序算法如冒泡排序、插入排序、快速排序和选择排序的概念和示例代码。
摘要由CSDN通过智能技术生成
  1. 顺序表(向量表、数组)

逻辑结构:一对一

存储结构:顺序存储

#define SIZE 5
typedef int data_t;

//描述一个顺序表的结构体
typedef struct List
{
    data_t data[SIZE];      //可以为任意数据类型此处为int
    int count;              //已经存入了count个元素
}List;

//在下标为iOffset处增加一个元素
int iOffset=1;
for(i=count;i>iOffset;i--)
{
    data[i] = data[i-1];
}
data[iOffset] = tData;
count++;

// 将下标为iOffset处的元素删除
iOffset = 1;
for(i=iOffset;i<count-1;i++)
{
    data[i] = data[i+1];
}
count--;
  1. 动态扩容顺序表

define SIZE 10
typedef int data_t;
//定义一个动态扩容数组结构体
typedef struct List
{
    data_t *pData;  //指向一个申请的数组,大小不够了申请更大的,把原来的释放掉
    int size;       //申请的空间大小  
    int count;        //已经存入的元素个数
}List;

/*
*功能:创建顺序表并初始化
*参数:无
*返回值:失败NULL,成功:顺序表的首地址
*/
List *creatList()
{
    List* pList = (List*)malloc(sizeof(List));
    if(NULL == pList)
    {
        return NULL;
    }
    memset(pList,0,sizeof(List));
    pList->size = SIZE;
    pList->pData = (data *)malloc(SIZE * sizeof(data_t));
    if(NULL == pList->pData)
    {
        return NULL;
    }
    memset(pList->pData,0,sizeof(data_t)*SIZE);
    pList->count = 0;
`    return pList;
}
/*
*功能:插入一个元素到顺序表中,空间不够重新申请
*参数:pList顺序表首地址;iOffset要插入元素的位置; tData要插入的元素
*返回值:失败-1,成功0
*/
int insertItemList(List* pList,int iOffset,data_t tData)
{
    //入参检查
    if(NULL==pList||iOffset<0||iOffset>pList->count)
    {
        return -1;
    }
    // 顺序表满时,申请更大的空间
    if(pList->count == pList->size)
    {
        int size = pList->size;
        pList->size += 5;
        data_t *pTemp = (data_t*)malloc(sizeof(data_t)*pList->size);
        if(NULL == pTemp)
        {
            return -1;
        }
        memset(pTemp,0,sizeof(data_t)*pList->size);
        //将原来空间的内容拷贝到新空间
        memcpy(pTemp,pList->pData,sizeof(data_t)*size);
        //将原来的空间释放
        free(pList->pData);
        pList->pData = pTemp;
    }
    int i;
    for(i=pList->count;i>iOffset;i--)
    {
        pList->PData[i] = pList->pData[i-1];
    }
    pList->pData[iOffset] = tData;
    pList->count++;
return 0;
}

/*
 * 功能:删除一个元素
 * pList 顺序表的首地址
 * iOffset 要删除位置的下标
 * pData 保存删除的元素
 */
int deleteItemList(List *pList, int iOffset, data_t *pData)
{
    if(NULL == pList || iOffset < 0 || iOffset >= pList->count || 0 == pList->count)
     {
        return -1;
     }

    int i;
    *pData = pList->pData[iOffset];
    for(i = iOffset; i < pList->count-1; i++)
    {
        pList->pData[i] = pList->pData[i+1];
    }
    pList->count--;
    return 0;
}
/*
*功能:销毁顺序表
*参数:List**ppList
*返回值: 无
*/
void destoryList(List **ppList)
{
    if(NULL == ppList || NULL == *ppList)
    {
        return;
    }

    free(*ppList);
    *ppList = NULL;
}
  1. 单向链表

逻辑结构:一对一

存储结构:不连续

节点由数据域与指针域组成

typedef struct data
{
    int a;
    char arr[10];
}Data_t;        //数据结构体

typedef struct Node
{
    Data_t data;        
    struct Node* pNext;//下一个节点的地址
}Node;        //节点结构体

typedef struct Link
{
    Node *pHead;//第一个节点的地址
    int count; //节点个数
}Link;       //单链表结构体

//头部插入
Node* pNode = NULL;
Link* pLink = NULL;
pNode->pNext = pLink->pHead;
pLink->pHead = pNode;
//中间插入(第iOffset个节点),前一个节点为pTemp
Node* pTemp = pLink->PHead;
for(i = 0;i<iOffst-1;i++)
{
    pTemp = pTemp->pNext;
}
pNode->pNext = pTemp->pNext;
pTemp->pNext = pNode;
//尾插
pTemp = pLink->pHead;
for(i = 0;i<count;i++)
{
    pTemp = pTemp->pNext;
}
pTemp->pNext = pNode;
//中间节点删除iOffset
Node* pTemp = pLink->PHead;
for(i = 0;i<iOffst-1;i++)
{
    pTemp = pTemp->pNext;
}
Node *pDel = pTemp->pNext;
pTemp->pNext = pDel->pNext;
free(pDel);
pDel = NULL;
/*此处为伪代码,未写边界条件判断条件,写时要加上不然会段错误*/
  1. 双向链表

节点由数据域与指针域<上一个节点的地址、下一个节点的地址>组成

typedef struct data
{
    int a;
    char b[10];
}Data_t;   //数据结构体

typedef struct node
{
    struct Node* pPri;//上一个节点地址
    Data_t data;    //数据
    struct Node* pNext;//下一个节点地址
}Node;        //节点结构体

typedef struct pDLink
{
    Node* pHead;
    int count;
}Dlink;// 双向链表结构体
//头部插入
Node * pNode = NULL;
Dlink* pDlink = NULL;
pNode->pNext = pDlink->pHead;
pDlink->ppHead->pPri = pNode;
pDlink->pHead = pNode;
//中间插<iOffset>先找到前一个节点pTemp
Node * pTemp =pDlink->pHead; 
for(i=0;i<iOffset-1;i++)
{
    pTemp = pTemp->pNext;
}
pNode->pNext = ptemp->pNext;
pTemp->pNext->pPri = pNode;
pTemp->pNext = pNode;
pNode->pPri = pTemp;
//尾插
pTemp = pDlink->pHead;
for(i = 0;i<count-1;i++)
{
    pTemp = pTemp->pNext;
}
pNode->pPri = pTemp;
pTemp->pNext = pNode;
//中间删(iOffset)找到前一个节点pTemp
pDel = pTemp->pNext
pDel->pNext->pPri = ptemp
pTemp->pNext = pDel->pNext
count--;
/*此处为伪代码,未写边界情况判断条件,写时要加上不然会段错误*/

遵循先进后出,,有顺序栈与链式栈((尾插+尾删)或(头插+头删)),只能在一端操作

栈顶下标iTop=-1

入栈iTop++; data[iTop] =Data;

出栈返回Data[iTop] ;iTop--;

typedef struct stack
{
    Data_t data[SIZE];
    int iTop;
}stack;
  1. 队列

遵循先进先出,有顺序队列与链式队列

typedef struct queue
{
    data_t data[SIZE];
    int iHead; //队头下标
    int iTail;//队尾下标
    int count; //队列元素个数
}
//入队
if(count == SIZE)
{
    printf("满了\r\n); 
   return 0
}
data[iTail] = data;
iTail++;
count++;
if(iTail == SIZE )
{iTail = 0}
//出队
if(count == 0)
{
    printf("没了");
    return 0 ;
}
*data = data[iHead];
iHead++;
count--;
if(iHead == SIZE )
{iHead = 0}
  1. 二叉树

  1. 哈希查找

  1. 排序算法

<1>冒泡排序

int i , j;
char arr[5] ={5,3,6,7,1};
for(i=0;i<4;i++)
{
    for(j =0;j<4-i;j++)
    {
        if(arr[j]<arr[j+1])
        {
            char temp = arr[j+1];
            arr[j+1] = arr[j];
            arr[j] = temp;
        }
    }
}

<2>插入排序

//从第二个元素开始,把元素值保存下来,让其与前一个元素比较,如果前一个大于它,将前一个元素后移一位,在与前前一个元素比较,直到前一个元素小于它或到达了第一个元素结束,将保存下来的值存到小于他的元素后面。-----有点像打牌,拿一张牌从右向左(大到小)依次比较,将其插入到小于他的右边
char arr[6]={2,6,3,4,5,1};
int len = strlen(arr);
int i,j;
for(i=1;i<len;i++)
{
    int key = arr[i];
    j  = i-1;
    while(j>=0 &&  arr[j]>arr[j+1])
    {
        arr[j+1] = arr[j];
        j--;
    }
    arr[j+1] = key;
}

<3>快速排序

//将首元素下标与尾元素下标记下(i与j),把首元素保存起来(x),用它与最后一个元素进行比较,如果最后一个元素大于他,j--用前一个元素继续比较,直到小于他,将此小于他的元素存到首位处即arr[i]处并i++;用此时i处的元素与x比较,如果arr[i]<x,i++,用后一个元素继续比较,如果arr[i]>x,将此处的arr[i]存到arr[j]处并j--;
//最后i=j时,把一开始保存的x存到arr[i],此时arr[i]左边小于他,右边的大于他,左边的元素下标为x-1,右边的下标为x+1,
//利用递归把左边的这一段用上面的方法再来一遍,此时首元素下标不变,尾元素下标为x-1;把由边的这一段用上面的方法再来一遍,此时尾元素下标不变,首元素下标为x+1,
char arr[10] = {4,2,5,1,3,6,8,6,9,15};
void speed(char *arr,int p,int q)
{
    if(p<q)
    {
        int i=p;//首元素下标
        int j=q;//尾元素下标
        char x = arr[i];
        while(i<j)
        {
            while(i<j&arr[j]>=x)
            {j--;}
            if(i<j){arr[i]= arr[j]; i++}
            while(i<=j&arr[i]<x)
            {i++;}
            if(i<j){arr[j]= arr[i]; j--}
        }
        arr[i]=x;
        speed(arr,p,i-1);
        speed(arr,i+1,q);
    }
return;
}

<4>选择排序

//设第一个成员为最小值,那后面的每一个与第一个比较,如果有比其更小的,将其下标记下,遍历比较完成后将最小的与第一个交换
char arr[6] = {5,3,2,9,4,1};
int len = strlen(arr);

int i,j;
for(i=0;i<len-1;i++)
{
   int min = i; 
    for(j=i+1;j<len-i;j++)
    {
        if(arr[j]<arr[min])
        {
            min = j
        }
    }
    char temp = arr[min];
    arr[min] = arr[i];
    arr[i] = temp;
}

<5>归并排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值