2024 数据结构

一、线性表

1、线性表的基本操作

在这里插入图片描述

1.1 线性表的顺序存储类型

静态分配

#define MaxSize 50    // 定义线性表最大长度
typedef struct{
	ElemType data[MaxSize];		// 顺序表的元素
	int length;			// 顺序表的当前长度
}SqList;		// 顺序表的类型定义

动态分配

#define InitSize 100    // 表长度的初始定义
typedef struct{
	ElemType *data;		// 指示动态分配数组的指针
	int MaxSize,length;			// 数组最大容量和个数
}SqList;		// 类型定义

C的初始动态分配语句为

L.data = (ElemType *)malloc(sizeof(ElemType)* InitSize);

1.2 顺序表上基本操作实现

1.2.1 插入操作

在L中位置i插入元素

bool ListInsert(SqList &L, int i, ElemType e){
	if(i < 1 || i > L.length + 1){   // 判断i是否有效
		return false;
	}
	if(L.length >= MaxSize){		// 判断当前存储空间是否已满
		return false;
	}
	for(int j = L.length; j >= i; j--){    // 将第i个元素及之后的元素后移
		L.data[j] = L.data[j - 1];
	}
	L.data[i - 1] = e;   // 在位置i插入元素
	L.length++;  	// 线性表长度+1
	return ture;
}
1.2.2 删除操作

在L中删除位置i的元素

bool ListInsert(SqList &L, int i, ElemType e){
	if(i < 1 || i > L.length ){   // 判断i是否有效
		return false;
	}
	e = L.data[i - 1];		// 记录删除元素
	for(int j = i; j < length; j++){    // 将第i个元素之后的元素前移
		L.data[j - 1] = L.data[j];
	}
	L.length--;  	// 线性表长度-1
	return ture;
}
1.2.2 按值查找(顺序查找)
int LocateElem(SqList L, ElemType e){
	for(int i = 0; i < L.length; i++){
		if(L.data[i] == e){
			return i + 1;		// 查找成功
		}
	}
	return 0;   // 退出循环,查找失败
}

2、课后大题

2.1

在这里插入图片描述

bool DeleteElem(SqList &L, ElemType &value){
	int k = 0;
	if(L.length == 0){
		return false;
	}
	value = L.data[0];
	for(int i = 1; i < L.length; i++){
		if(L.data[i] < value){
			value = L.data[i];
			k = i;
		}
	}
	L.data[k] = L.data[L.length - 1];
	}
	L.length--;
	return 0;   // 退出循环,查找失败
}

2.2

在这里插入图片描述

void reverse(SqList &L){
	ElemType temp;
	for(int i = 0; i <  L.length / 2; i++){
		temp = L.data[i];
		L.data[i] = L.data[L.length - i - 1];
		L.data[L.length - i - 1] = temp;
	}
}

2.3

在这里插入图片描述

// 方法一
void DeleteX(SqList &L, ElemType x){
	if(L.length == 0){
		return false;
	}
	int j = 0;
	for(int i = 0; i < L.length; i++){
		if(L.data[i] != x){
			L.data[j] = L.data[i];
			j++;
		}	
	}
	L.length = j + 1;
}
// 方法二
void DeleteX(SqList &L, ElemType x){
	if(L.length == 0){
		return false;
	}
	int i = 0, k = 0;
	while(i < L.length){
		if(L.data[i] == x){
			k++;
		}
		else{
			L.data[i - k] = L.data[i];   // 当前元素前移k个位置
		}
		i++;
	}
	L.length -= k;
}

2.4

此题意在有序顺序表的整体删除,但较麻烦,故采用上题方法一
在这里插入图片描述

bool DeleteElem(SqList &L, int s, int t){
	if(s > t || L.length == 0){
		return false;
	}
	int j = 0;
	for(int i = 0; i < L.length; i++){
		if(L.data[i] < s or L.data[i] > t){
			L.data[j] = L.data[i];
		}
	}
	L.length = j;
	return true;
}

2.5

在这里插入图片描述

bool DeleteElem(SqList &L, int s, int t){
	if(s > t || L.length == 0){
		return false;
	}
	int j = 0;
	for(int i = 0; i < L.length; i++){
		if(L.data[i] < s or L.data[i] > t){
			L.data[j] = L.data[i];
		}
	}
	L.length = j;
	return true;
}

2.6

在这里插入图片描述

void DeletesameNum(SqList &L){
	int i, j;
	for(i = 0, j = 1; j < L.length; j++){
		if(L.data[i] != L.data[j]){
			L.data[++i] = L.data[j];
		}
	L.length = i + 1;
	}
}

2.7

在这里插入图片描述

bool combine(SqList L1, SqList L2, SqList &L3){
    if(l1.length + L2.length > maxSize){
        return false;
    }
    
    int i = 0, j = 0, k = 0;
    while(i != L1.length && j != L2.length){
        if(L1.data[i] < L.data[j]){
            L3.data[k++] = L1.data[i++];
        }
        else{
            L3.data[k++] = L2.data[j++];

        }
      }
      
      while(i != L1.length){
        L3.data[k++] = l1.data[i++];
      }  
      while(j != L2.length){
        L3.data[k++] = l2.data[j++];
      } 
      L3.length = k;
      return true;
}

2.8

在这里插入图片描述

typedef int DataType;

void reverse(DataType A[], int left, int right, arraySize){
    if(left >= right || right >= arraySize){
        return false;
    }
    int mid = (left + right) / 2;
    for(int i = 0; i <= mid - left; i++){
        DataType temp = A[left + i];
        A[left + i] = A[right - i];
        A[right - i] = temp;
    }
}

void Exchange(DataType A[], int m, int n, int arraySize){
    reverse(A, 0, m + n - 1, arraySize);   // 整体逆置
    reverse(A, 0, n - 1, arraySize);        // 逆置b
    reverse(A, n, m + n - 1, arraySize);    // 逆置a
}

2.9

在这里插入图片描述
题目要求最少时间,使用折半查找

void Makex(ElemType A[], ElemType x){
    int low = 0, high = n - 1, mid;
    while(low <= high ){		//折半查找
        mid = (low + high) / 2;
        if(A[mid] == x){
        	break;
        }
        else if(A[mid] < x){
        	low = mid + 1;
        }
        else{
        	high = mid - 1;
        }
    }

	// 两个if执行一个
	if(A[mid] == x && mid != n - 1){	// 若最后一个元素等于x,则不存在交换
		int t = A[mid];
		A[mid] = A[mid + 1];
		A[mid + 1] = t;
	}
    if(Low > high){
        for(i = n - 1; i > high; i--){
            A[i] = A[i - 1];
        }
       A[i] = x;
    }
}

2.10

在这里插入图片描述

void Makex(ElemType A[], int n, int p){
    reverse(A, 0, p - 1);   // 前半部分(p)逆置
    reverse(A, p, n - 1);   // 后半部分( n - p)逆置
    reverse(A, 0, n - 1);   // 整体逆置
}
void reverse(ElemType A[], int left, int right){
    int i, temp;
    for(i = 0; i < (right - left + 1) / 2; i++){
        temp = A[left + i];
        A[left + i] = A[right - i];
        A[right - i] = temp;
    }
}

2.11

在这里插入图片描述

int search(int A[], int B[], int n){
    int s1 = 0, d1 = n - 1, m1, s2 = 0, d2 = n - 1, m2;  // 分别表示序列A和B的首位数、末尾数、中位数
    while(s1 != d1 || s2 != d2){
        m1 = (s1 + d1) / 2;
        m2 = (s2 + d2) / 2;
        if(A[m1] == B[m2]){     // 若a=b,则a或b是所求中位数
            return A[m1];
        }
        if(A[m1] < B[m2]){          // 若a<b,则舍弃A中较小一半和B中较大一半
            if((s1 + d1) % 2 == 0){     // 元素个数为奇数
                s1 = m1;        // 舍弃A中间点以前的部分
                d2 = m2;        // 舍弃B中间点以后的部分
            }
            else{           // 元素个数为偶数
                s1 = m1 + 1;    // 舍弃A中间点和中间点以前的部分
                d2 = m2;        // 舍弃B中间点以后的部分
            }
        }
        else{     // 若a>b,则舍弃A中较大一半和B中较小一半
            if((s2 + d2) % 2 == 0){     // 元素个数为奇数
                d1 = m1;        // 舍弃A中间点以后的部分
                s2 = m2;        // 舍弃B中间点以前的部分
            }
            else{               // 元素个数为偶数
                d1 = m1;        // 舍弃A中间点以后的部分
                s2 = m2 + 1;    // 舍弃B中间点和B中间点以前的部分
            }
        }
    }
    return A[s1] < B[s2] ? A[s1]:B[s2];
}

2.12

在这里插入图片描述

int search(int A[], int n){
    int i, c, count = 1;    // c用来保存候选主元素,count用来计数
    c = A[0];
    for(i = 1; i < n; i++){
        if(A[i] == c){
            count++;        // 候选主元素计数
        }
        else{
            if(count > 0){    // 处理不是候选主元素的情况
                count--;
            }
            else{            // 更换候选主元素,重新计数
                c = A[i];
                count = 1;       
            }

        }
    }
    
    if(count > 0){
        for(i = count = 0; i < n; i++){     // 统计主元素出现次数
            if(A[i] == c){
                count++;
            }
        }
    }
    if(count > n / 2){
        return c;   // 确认候选主元素
    }
    else{
        return -1;   // 不存在主元素
    }
}

2.13

在这里插入图片描述

int MinNum(int A[], int n){
    int i, *B;    
    B = (int *)malloc(sizeof(int)*n);
    
    memset(B, 0,sizeof(int)*n);   // 赋初值为0
    for(i = 0; i < n; i++){
        if(A[i] > 0 && A[i] < n){
            B[A[i] - 1] = 1; 
        }
    }
    for(i = 0; i < n; i++){
        if(B[i] == 0){
            break;
        }
    }
    return i + 1;
}

2.14

在这里插入图片描述
在这里插入图片描述

#define Int_Max 0x7fffffff

int abs(int a){     // 计算绝对值
    if(a < 0){
        return -a;
    }
    else{
        return a;
    }
}

    
bool min(int a, int b, int c){     // a是否是三个数中最小值
    if(a <= b && a <= c){
        return true;
    }
    return false;
}   

int findMin(int A[], int n, int B[], int m, int C[], int p){
    int i = 0, j = 0, k = 0, D_min = Int_Max, D;
    while(i < n && j < m && K < p && D_min > 0){
        D = abs(A[i] - B[j]) + abs(B[j] - C[k]) + abs(C[k] - A[i]);
        if(D < D_min){
            D_min = D;
        }
        if(min(A[i], B[j], C[k])){
            i++;
        }
        else if(min(B[j], C[k], A[i])){
            j++;
        }
        else{
            k++;
        }
    }
    return D_min;
}

3、链表

3.1单链表

线性表的链式存储又称单链表。对于每个链表结点,除了存放元素自身信息之外,还要存放一个指向后继结点的指针。
单链表结点类型描述如下:

typedef struct LNode{
	ElenType data;			// 数据域
	struct LNode *next;		// 指针域
}LNode, *LinkList;

3.2 单链表基本操作实现

3.2.1 头插法

在这里插入图片描述

LinkList List_HeadInsert(LinkList &L){
        LNode *s;
        int x;
        L = (LinkList)malloc(sizeof(LNode));    // 创建头结点
        L->next = NULL;         // 初始为空链表
        scanf("%d", &x);
        while(x != 9999){   // 输入9999表示结束
            s = (LNode *)malloc(sizeof(LNode));
            s->data = x;
            
            s->next = L->next;
            L->next = s;
            
            scanf("%d", &x);
        }
        return L;
}
3.2.2 尾插法

在这里插入图片描述

LinkList List_HeadInsert(LinkList &L){
        int x;
        L = (LinkList)malloc(sizeof(LNode));    // 创建头结点
         LNode *s, *r = L;		// r为尾指针
        scanf("%d", &x);
        while(x != 9999){   // 输入9999表示结束
            s = (LNode *)malloc(sizeof(LNode));
            s->data = x;
            
            r->next = s;
            r = s;
            
            scanf("%d", &x);
        }
                r->next = NULL;         // 尾结点指针置空
        return L;
}
3.2.3 按序号查找结点
LNode *GetElem(LinkList L, int i){
    if(i < 1){
        return NULL;
    }
    int j = 1;
    LNode *p = L->next;     // 第一个结点指针赋给p
    while(p != NULL && j < i){
        p = p->next;        // 这里j小于i,但是p已经指向了下一结点,也就是第i个结点
        j++;
    }
    return p;
}
3.2.4 按值查找结点
LNode *GetElem(LinkList L, ElemType e){
    LNode *p = L->next;     // 第一个结点指针赋给p
    while(p != NULL && p->data != e){
        p = p->next;        // 这里j小于i,但是p已经指向了下一结点,也就是第i个结点
    }
    return p;
}
3.2.5 插入结点

在这里插入图片描述

p = GetElem(L, i - 1);		// 查找插入位置的前驱结点
s->next = p->next;
p->next = s->next;
3.2.6 删除结点

在这里插入图片描述

p = GetElem(L, i - 1);		// 查找删除位置的前驱结点
q = p->next;
p->next = q->next;
free(q);

3.3 双链表

在这里插入图片描述

typedef struct DNode{
    ElemType data;
    struct DNode *prior, *next;
}DNode, *DLinklist;
3.3.1 双链表插入结点

在这里插入图片描述

s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
3.3.2 双链表删除结点

在这里插入图片描述

p->next = q->next;
q->next->prior = p;
free(q);

3.4 循环链表

3.4.1 循环单链表

在这里插入图片描述

3.4.2 循环双链表

在这里插入图片描述

4、课后大题

4.1

在这里插入图片描述

void Delx(LinkList &L, ElenType x){
    LNode *p;       // p指向删除结点
    if(p == NULL){
        return;     // 递归出口
    }
    if(L->data == x){
        p = L;
        L = L->next;
        free(p);
        Delx(L, x);
    }
    else{
        Delx(L->next, x);   // 递归调用
    }
}

4.2

在这里插入图片描述

void Delx(LinkList &L, ElenType x){
    LNode *p = L->next, *pre = L, *q;       
    while(p != NULL){
        if(p->data == x){
            q = p;
            p = p->next;
            pre->next = p;
            free(q); 
        }
        else{
            pre = p;
            p = p->next;
        }
    }
}

4.3

在这里插入图片描述

void R_Print(LinkList L){
    if(L->next != NULL){
        R_Print(L->next);
    }
    if(L != NULL){
        print(L->data);
    }
}

void R_head(LinkList L){
    if(L->next != NULL){
        R_Print(L->next);
    }
}

4.4

在这里插入图片描述

LinkList Del_Min(LinkList &L){
    LNode *pre = L, *p = L->next, *min = L->next, *minpre = L;
    while(p != NULL){
        if(min->data > p->data){
            min = p;
            minpre = pre;
        }
        pre = p;
        p = p->next;
    }
    minpre->next = min->next;
    free(min);
    return L;
}

4.5

在这里插入图片描述

LinkList Reverse 1(LinkList L){
    LNode *p, *r;
    p = L->next;
    L->next = NULL;
    while (p!=NULL) {
        r = p->next;
        p->next = L->next;
        L->next = p;
        p = r;
    }
    return L;
}

4.6

在这里插入图片描述

LinkList reverseInsert(LinkList &L){
    LNode *p = L->next, *pre;
    LNode *r = p->next;
    p->next = NULL;     // 构造只含一个数据结点的有序表
    p = r;
    while(p != NULL){
        r = p->next;           // 防断链
        pre = L;    // 每次都从头开始判断大小
        while(pre->next != NULL && pre->next->data < p->data){
            pre = pre->next;    // 找到插入p的前驱结点pre
        }
        p->next = pre->next;    // 将p插入pre后
        pre->next = p;
        p = r;
    }
    return L;
}

4.7

在这里插入图片描述

void delete(LinkList &L, int min, int max){
    LNode *r = L, *p = L->next;
    while (p != NULL){
        if(p->data > min && p->data < max){
            r->next = p->next;
            free(p);
            p = r->next;
        }
        else{
            r = p;
            p = p->next;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值