掌握这些,玩转数据结构!

数据结构里那些你必须掌握的

线性表

顺序表

  • 数据结构

#define MaxSize 100
typedef struct{
	ElementType data[Maxsize];
	int length;
}sqList;
  • 相关操作

    1. 在第i个位置插入元素e
    bool insert(sqList &L,int i,ElementType e)
    {
    	if(i<1||i>L.length+1)
    		return false;
    	for(int j=L.length;j>=i;j--)
    		L.data[j]=L.data[j--];
    	L.data[i-1]=e;
    	L.length++;
    	return true;
    }
    

    平均移动次数:n/2

    2. 删除第i个元素
    bool del(sqList &L,int i,ElementType &e)
    {
    	if(i<1||i>L.length)
    		return false;
    	e=L.data[i-1];
    	for(int j=i;j<L.length;j++)
    		L.data[j--]=L.data[j];
    	L.length--;
    	return true;
    }
    

    平均移动次数:(n-1)/2

    3. 按值查找
         int Locate(sqList L,ElementType e)
         {
         	for(int i=0;i<L.length;i++)
         		if(L.data[i]==e)
         			return i+1;
         	return 0;
         }
    

    平均移动次数:(n+1)/2

单链表

  • 数据结构

    typedef struct LNode{
    	ElementType data;
    	struct LNode *next;
    }LNode, *LinkList;
    
  • 相关操作(有头结点)

    1. 头插法建立单链表
    LinkList List_HeadInsert(LinkList &L)
    {
    	LNode *p;int x;
    	L=new LNode;  //创建头结点
    	L->next=NULL;
    	cin>>x;
    	while(!cin.eof())
    	{
    		p=new LNode;
    		p->data=x;
    		p->next=L->next;
    		L->next=p;
    	 } 
    	return L;
    }
    
    2. 尾插法建立单链表
    LinkList List_TailInsert(LinkList &L)
    {
    	int x;
    	L=new LNode;  //创建头结点
    	LNode *p,*r=L;  //尾指针 
    	L->next=NULL;
    	cin>>x;
    	while(!cin.eof())
    	{
    		p=new LNode;
    		p->data=x;
    		r->next=p; 
    		r=p;
    	} 
    	r->next=NULL;
    	return L;
    }
    
    3. 按序号查结点
    LNode *GetElem(LinkList L,int i)
    {
    	int cnt=1;
    	LNode *p=L->next;
    	if(i==0)
    		return L;
    	if(i<1)
    		return NULL;
    	while(p&&cnt<j)
    	{
    		p=p->next;
    		cnt++;
    	}
    	return p;
    }
    
    4. 按值查结点
    LNode *LocateElem(LinkList L,ElementType e)
    {
    	LNode *p=L->next;
    	while(p&&p->data!=e)
    		p=p->next;
    	return p;
    }
    
    5. 在第i个位置插入结点
    bool insert(LinkList L,ElementType e)
    {
    	LNode *p=GetElem(L,i-1);
    	if(p==NULL)
    		return false;
    	LNode *q=new LNode;
    	q->next=p->next;
    	p->next=q;
    	return true;
    }
    
    6. 删除第i个结点
    bool del(LinkList L,ElementType e)
    {
    	LNode *p=GetElem(L,i-1);
    	if(p==NULL)
    		return false;
    	LNode *q=p->next;
    	p->next=q->next;
    	delete q;
    	return true;
    }
    

双链表

  • 数据结构

    typedef struct DNode{
    	ElemType data;
    	struct DNode *pre,*next;
    }DNode,*DLinklist;
    
  • 相关操作

    1. *p结点后插入 *s
    void insert(DLinklist &L,DNode p,ElemType e)
    {
    	DNode *s=new DNode;
    	s->data=e;
    	s->next=p->next;
    	p->next->pre=s;
    	p->next=s; 
    	s->pre=p; 
    }
    
    2. 删除*p结点后 *q
    void del(DLinklist &L,DNode p)
    {
    	DNode *q=p->next;
    	p->next=q->next;
    	q->next->pre=p;
    	delete q; 
    }
    

顺序栈

  • 数据结构

    #define MaxSize 100
    typedef struct {
    	elemType data[MaxSize];
    	int top; //指向栈顶元素
    }SqStack;
    
  • 相关操作

    1. 初始化
    void initStack(SqStack &S)
    {
    	S.top=-1;
    }
    
    2. 判断栈空
    void StackEmpty(SqStack S)
    {
    	if(S.top=-1)
    		return true;
    	else return false;
    }
    
    3. 进栈
    bool push(SqStack &S,ElemType x)
    {
    	if(S.top==MaxSize-1)
    		return false;
    	S.data[++S.top]=x;
    	return true;
    }
    
    4. 出栈
    bool pop(SqStack &S,ElemType &x)
    {
    	if(S.top==-1)
    		return false;
    	x=S.data[S.top++];
    	return true;
    }
    
    5. 读栈顶
    bool getTop(SqStack S,ElemType &x)
    {
    	if(S.top==-1)
    		return false;
    	x=S.data[S.top];
    	return true;
    }
    

链栈

栈的应用

  • 括号匹配

    #include <iostream>
    #include <stack>
    #include <string>
    using namespace std;
    
    int main()
    {
    	int cnt = 0;
    	string s;
    	stack<char> S;
    	cout << "请输入判断的括号字符串:" << endl;
    	cin >> s;
    	for (int i = 0; i < s.length(); i++)
    	{
    		if (s[i] == '[' || s[i] == '(' || s[i] == '{')
    		{
    			S.push(s[i]);
    		}
    		else if (s[i] == ']')
    		{
    			if (S.top() == '[')
    			{
    				cnt++;
    				S.pop();
    			}
    			else
    				break;
    		}
    		else if (s[i] == ')')
    		{
    			if (S.top() == '(')
    			{
    				cnt++;
    				S.pop();
    			}
    		}
    		else if (s[i] == '}')
    		{
    			if (S.top() == '{')
    			{
    				cnt++;
    				S.pop();
    			}
    		}
    	}
    	if(S.empty())
    		cout << "配对成功,共" << cnt << "对括号";
    	else
    		cout << "配对失败!";
    }
    
  • 求后缀表达式

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;

//栈内优先级
int isp(char c)
{
	if (c == '#')
	{
		return 0;
	}
	else if (c == '(')
	{
		return 1;
	}
	else if (c == '+' || c == '-')
	{
		return 3;
	}
	else if (c == '*' || c == '/')
	{
		return 5;
	}
	else if (c == ')')
	{
		return 6;
	}
}

//栈外优先级
int icp(char c)
{
	if (c == '#')
	{
		return 0;
	}
	else if (c == '(')
	{
		return 6;
	}
	else if (c == '+' || c == '-')
	{
		return 2;
	}
	else if (c == '*' || c == '/')
	{
		return 4;
	}
	else if (c == ')')
	{
		return 1;
	}
}

string change(string str)
{
    string S;
    stack<int> data;
    stack<char> op;
    op.push('#');
    str += '#';
    int index = 0;
    while (index < str.size())
    {
        if (str[index]>='0'&&str[index]<='9')   
        {
            string s2;
            while(str[index]>='0'&&str[index]<='9')  //防止数字被拆开压栈
			{
                s2+=str[index];
                index++;
            }
            data.push(stoi(s2));  
            S+=to_string(data.top());
            S+=" ";
        }
        else
        {
            if (icp(str[index]) == isp(op.top()))
            {
                op.pop();
                index++;
            }
            else if (icp(str[index]) > isp(op.top()))
            { //运算符进栈
                op.push(str[index]);
                index++;
            }
            else
            {
                if (op.top() == ')')
                { //如果该运算符是右括号,则直接弹出
                    op.pop();
                }
                else
                {
                    S += op.top(); //输出
                    S+=" ";
                    op.pop();
                }
            }
        }
    }
  return S;
}
  • 后缀表达式求值

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;

//栈内优先级
int isp(char c)
{
    if (c == '#')
    {
        return 0;
    }
    else if (c == '(')
    {
        return 1;
    }
    else if (c == '+' || c == '-')
    {
        return 3;
    }
    else if (c == '*' || c == '/')
    {
        return 5;
    }
    else if (c == ')')
    {
        return 6;
    }
}

//栈外优先级
int icp(char c)
{
    if (c == '#')
    {
        return 0;
    }
    else if (c == '(')
    {
        return 6;
    }
    else if (c == '+' || c == '-')
    {
        return 2;
    }
    else if (c == '*' || c == '/')
    {
        return 4;
    }
    else if (c == ')')
    {
        return 1;
    }
}


int main()
{
    cout << "请输入中缀表达式:" << endl;
    string s, ss;
    cin>>s;
    ss = change(s);
    cout << "后缀表达式为:" <<ss<< endl;
    stack<int> data;
    for (int i = 0; i < ss.length(); i++)
    {
        if (ss[i] >= '0' && ss[i] <= '9')
        {
        	string s2;
            while(ss[i]>='0'&&ss[i]<='9')   //防止数字被拆开压栈,保持整数完整性
			{
                s2+=ss[i];
                i++;
            }
            data.push(stoi(s2));
		}
		else if(ss[i]==' ')
			continue;
        else
        {
            int res = 0;
            int x, y;
            y = data.top();
			data.pop();
            x = data.top();
            data.pop();
            if (ss[i] == '+')
                res = x + y;
            else if (ss[i] == '-')
                res = x - y;
            else if (ss[i] == '*')
                res = x * y;
            else
                res = x / y;
            data.push(res);
        }
    }
    cout << "表达式的结果为:" << data.top() << endl;
    return 0;
}
  • 中缀表达式求值

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;

int opcmp(char a, char b)
{
    if ((a == '*' || a == '/') && (b == '+' || b == '-' || b == '(' || b == '#'))
        return 1;
    else if ((a == '+' || a == '-') && (b == '(' || b == '#'))
        return 1;
    else
        return 0;
}
//计算运算值栈顶两个元素(a栈顶第一个元素,b栈顶第二个元素)
int calculate(char c, int a, int b)
{
    int res = 0;
    switch (c)
    {
    case '+':
        res = b + a;
        break;
    case '-':
        res = b - a;
        break;
    case '*':
        res = b * a;
        break;
    case '/':
        res = b / a;
        break;
    }
    return res;
}

int main()
{
    stack<int> data;
    stack<char> op;
    op.push('#');
    cout << "请输入中缀表达式:" << endl;
    string s;
    cin >> s;
    int i = 0;
    while (i < s.length())
    {
        if (s[i] >= '0' && s[i] <= '9') //数字直接进栈
        {
            string ss;
            while (s[i] >= '0' && s[i] <= '9') //防止数字被拆开压栈,保持整数完整性
            {
                ss += s[i];
                i++;
            }
            data.push(stoi(ss));
        }

        else //运算符
        {
            char x = s[i];
            char y = op.top();
            if (x == '(' || opcmp(x, y)) //优先级高入栈
                op.push(x);
            else
            {
                if (x == ')') //右括号,一直运算直到左括号出栈
                {
                    while (y != '(')
                    {
                        int a = data.top();
                        data.pop();
                        int b = data.top();
                        data.pop();
                        data.push(calculate(y, a, b));
                        op.pop();
                        y = op.top();
                    }
                    op.pop();
                }
                else //优先级低运算出栈直到遇到高的再进栈
                {
                    while (!opcmp(x, y))
                    {
                        int a = data.top();
                        data.pop();
                        int b = data.top();
                        data.pop();
                        data.push(calculate(y, a, b));
                        op.pop();
                        y = op.top();
                    }
                    op.push(x);
                }
            }
            i++;
        }
    }
    while (op.top()!='#')
    {
        char y = op.top();
        int a = data.top();
        data.pop();
        int b = data.top();
        data.pop();
        data.push(calculate(y, a, b));
        op.pop();
    }
    cout << "运算结果为:" << data.top() << endl;
}

队列

顺序队列

  • 数据结构

    #define MaxSize 50
    typedef struct{
    	ElemType data[MaxSize];
    	int front,rear;
    }SqQueue; 
    

循环队列

  • 数据结构

    #define MaxSize 50
    typedef struct{
    	ElemType data[MaxSize];
    	int front,rear;
    }SqQueue; 
    
  • 相关操作

    1. 初始化
    void init(SqQueue &Q)
    {
        Q.rear=Q.front=0;
    }
    
    2. 判断队列是否空
    bool empty(SqQueue Q)
    {
    	if(Q.front==Q.rear)
    		return true;
    	else 
    		return false;
    }
    
    3. 入队
    bool enQueue(SqQueue &Q,ElemType x)
    {
    	if((Q.rear+1)%MaxSize==Q.front)  //队满 
    		return false;
    	Q.data[Q.rear]=x;
    	Q.rear=(Q.rear+1)%MaxSize;
    	return true; 
    }
    
    4. 出队
    bool deQueue(SqQueue &Q,ElemType &x)
    {
    	if(Q.front==Q.rear)  //队空 
    		return false;
    	x=Q.data[Q.front];
    	Q.front=(Q.front+1)%MaxSize;
    	return true; 
    }
    

    队满:(Q.rear+1)%MaxSize==Q.front

    队空:Q.front==Q.rear

    队中元素个数:(Q.rear-Q.front+MaxSize)%MaxSize

链队

  • 数据结构

    typedef struct LinkNode{
    	ElemType data;
    	struct LinkNode *next;
    }LinkNode;
    typedef struct{
    	LinkNode *front,*rear;
    }LinkQueue;
    
  • 相关操作(有头结点)

    1. 初始化
    void init(LinkQueue &Q)
    {
    	Q.front=Q.rear=new LinkNode;  //建立头结点 
    	Q.front->next=NULL;
    }
    
    2. 判队空
    void empty(LinkQueue Q)
    {
    	if(Q.front==Q.rear) return true;  //建立头结点 
    	return false;
    }
    
    3. 入队
    void enQueue(LinkQueue &Q,ElemType x)
    {
    	LinkNode *p=new LinkNode;
    	p->data=x;
    	p->next=NULL;
    	Q.rear->next=p;
    	Q.rear=p; 
    }
    
    4. 出队
    bool deQueue(LinkQueue &Q,ElemType &x)
    {
        if(Q.rear==Q.front)  return false;
    	LinkNode *p=Q.front->next;
        x=p->data;
        Q.font->next=p->next;
        if(Q.rear=p)  //若只剩最后一个结点,尾指针头指针都指向头结点
            Q.rear=Q.front;
        delete p;
        return true;
    }
    

二叉树

  • 数据结构

    typedef struct BiTNode
    {
        ElemType data;
        struct BiTNode *lchild, *rchild;
    }BiTNode,*BiTree;
    
  • 相关操作

    以下图为例在这里插入图片描述
    1 2 0 4 6 0 0 0 3 0 5 0 0

    1. 初始化建树
    void create(BiTree &T)
    {
      int x;
        cin >> x;
      if (x == 0)
            T = NULL;
        else
        {
            T = new BiTNode;
            T->data = x;
            create(T->lchild);
            create(T->rchild);
        }
    }
    
    2. 先序遍历
    void preOrder(BiTree T)
     {
         if(T!NULL)
         {
             visit(T);
             preOrder(T->lchild);
             preOrder(T->rchild);
         }
    
    3. 中序遍历
    void inOrder(BiTree T)
    {
        if(T!NULL)
        {
            inOrder(T->lchild);
            visit(T);
            inOrder(T->rchild);
        }
    }
    
    4. 后序遍历
    void postOrder(BiTree T)
    {
        if(T!NULL)
        {
            postOrder(T->lchild);
            postOrder(T->rchild);
            visit(T);				
    	}
    }
    
    5. 统计度为0结点个数
    void degree0(BiTree T, int &res)
      {
          if (T != NULL)
          {
              if (T->lchild == NULL && T->rchild == NULL)
              {
                  T->visit();
                  res++;
              }
              degree0(T->lchild, res);
              degree0(T->rchild, res);
          }
      }
    
    6. 统计度为1结点个数
    void degree1(BiTree T, int &res)
    {
       if (T != NULL)
       {
           if (T->lchild == NULL && T->rchild != NULL || T->lchild != NULL && T->rchild == NULL)
           {
               T->visit();
               res++;
           }
           degree1(T->lchild, res);
           degree1(T->rchild, res);
       }
    }
    
    7. 统计度为2结点个数
     void degree2(BiTree T, int &res)
      {
          if (T != NULL)
          {
              if (T->lchild != NULL && T->rchild != NULL)
              {
                  T->visit();
                  res++;
              }
              degree2(T->lchild, res);
              degree2(T->rchild, res);
          }
      }
    
    8. 树的高度
    void height(BiTree T, int &res, int &cnt)
        {
            if (T != NULL)
            {
                cnt++;
                height(T->lchild, res, cnt);
                res = max(cnt, res);
                height(T->rchild, res, cnt);
                res = max(cnt, res);
                cnt--;
            }
        }
        
    int height(BiTree T)
    {
        if (T == NULL)
            return 0;
        int lh = height(T->lchild);
        int rh = height(T->rchild);
        return max(lh + 1, rh + 1);
    }
    
    9. 树的宽度
    queue<BiTree> Q;
    int width(BiTree T)
    {
       int res = 0, cnt = 0;
       Q.push(T);
       while (!Q.empty())
       {
           cnt = Q.size();
           res = max(res, cnt);
           for (int i = 0; i < cnt; i++)
           {
               BiTNode *p;
               p = Q.front();
               Q.pop();
               if (p->lchild != NULL)
               {
                   Q.push(p->lchild);
               }
               if (p->rchild != NULL)
               {
                   Q.push(p->rchild);
               }
           }
       }
       return res;
    }
    
    10. 删除所有叶子结点
    void delLeaf(BiTree &T, BiTree &t)
    {
        if (T != NULL)
        {
            if (T->lchild == NULL && T->rchild == NULL)
            {
               if(t!=NULL)  
                  //t为NULL时只有根节点,只需删除T指针,若不为根节点修改T的父节点的左右指针
                {
                    if (T == t->lchild)
                        t->lchild = NULL;
                    else
                        t->rchild = NULL;
                }
                delete (T);
                return;
            }
            t = T;
            delLeaf(T->lchild, t);
            delLeaf(T->rchild, t);
        }
    }
    
    11. 计算指定结点*p的层次
    void doLevel(BiTree T, int x, int l, int &level)
      {
          if (T)
          {
              if (T->data == x)
              {
                  level = l;
                  return;
              }
              else
              {
                  doLevel(T->lchild, x, l+1, level);
                  doLevel(T->rchild, x, l+1, level);
              }
          }
      }
    
    12. 计算二叉树结点中最大元素的值
    void calMax(BiTree T, int &m)
     {
         if (T)
         {
             m = max(T->data, m);
             calMax(T->lchild, m);
             calMax(T->rchild, m);
         }
     }
    
    13. 交换每个结点的孩子
        void swap(BiTree &T)
        {
            if(T)
            {
                BiTNode *p;
                p = T->lchild;
                T->lchild=T->rchild ;
                T->rchild= p;
                swap(T->lchild);
                swap(T->rchild);
            }
        }
    
    14. 先序次序输出所有结点数值及所在层次
     void preLevel(BiTree T, int l)
          {
              if (T)
              {
                  cout << "结点" << T->data << "的层次为:" << l << endl;
                  preLevel(T->lchild, l+1);
                  preLevel(T->rchild, l+1);
              }
          }
    

线索二叉树

  • 数据结构

    typedef struct ThreadNode
    {
        char data;
        ThreadNode *lchild;
        ThreadNode *rchild;
        int ltag; // 0表示有孩子,1表示线索
        int rtag;
    } ThreadNode,* ThreadTree;
    
  • 相关操作

    以 1 2 0 4 6 0 0 0 3 0 5 0 0为例

    1. 构造中序线索二叉树
    void visit(ThreadTree &pre)
        {
            if (this->lchild == NULL)
            {
                this->lchild = pre;
                this->ltag = 1;
            }
            if (pre != NULL && pre->rchild == NULL)
            {
                pre->rchild = this;
                pre->rtag = 1;
            }
            pre = this;
        }
    void inThread(ThreadTree &T, ThreadTree &pre)
    {
        if (T)
        {
            inThread(T->lchild, pre);
            T->visit(pre);
            inThread(T->rchild, pre);
        }
    }
    
    void createInThread(ThreadTree T)
    {
        if (T)
        {
            ThreadNode *pre = NULL;
            inThread(T, pre);
         if(pre->rchild == NULL) //处理最后一个结点
             	pre->rtag = 1;
        }
    }
    
    2. 遍历中序线索二叉树
    
    ThreadNode *firstNode(ThreadNode *p) //找最左下角结点
     {
         while (p->ltag == 0)
             p = p->lchild;
         return p;
     }
     
     ThreadNode *nextNode(ThreadNode *p)
     {
         if (p->rtag == 0)
             return firstNode(p->rchild); 
         						//若后继没有被线索化,该结点的后继则是右子树最左下角结点
         else
             return p->rchild;
     }
     
     void inOrder(ThreadTree T)
     {
         for (ThreadNode *p = firstNode(T); p != NULL; p = nextNode(p))
             p->visit();
     }
    
    3. 逆向遍历中序线索二叉树
    ThreadNode *lastNode(ThreadNode *p) //找最右下角结点
     {
         while (p->rtag == 0)
             p = p->rchild;
         return p;
     }
     
     ThreadNode *preNode(ThreadNode *p)
     {
         if (p->ltag == 0)
             return lastNode(p->lchild); 
         						//若前驱没有被线索化,该结点的前驱则是左子树最右下角结点
         else
             return p->lchild;
     }
     
     void reInOrder(ThreadTree T)
     {
         for (ThreadNode *p = lastNode(T); p != NULL; p = preNode(p))
             p->visit();
    
    4. 构造先序线索二叉树
         void preThread(ThreadTree &T, ThreadTree &pre)
         {
             if (T)
             {
                 T->visit(pre);
                 if (T->ltag == 0) //防止先线索化后走到前驱结点遍历时再走回来,原地打圈
                     preThread(T->lchild, pre);
                 if (T->rtag == 0)
                 	preThread(T->rchild, pre);
                 			//防止先线索化后走到后继结点遍历时再走回来,原地打圈
             }
         }
         
         void createPreThread(ThreadTree T)
         {
             if (T)
             {
                 ThreadNode *pre = NULL;
                 preThread(T, pre);
                 if(pre->rchild == NULL) //处理最后一个结点
                  	pre->rtag = 1;
             }
         }
    
    5. 遍历先序线索二叉树
    ThreadNode *nextNode(ThreadNode *p)
     {
         if (p->rtag == 0) //未被线索化
         {
             if (p->ltag == 0)
                 return p->lchild; //有左孩子,后继为左孩子
         }
         return p->rchild; //被线索化或没被线索化无左孩子,后继都为右孩子
     }
     
     void preOrder(ThreadTree T)
     {
         for (ThreadNode *p = T; p != NULL; p = nextNode(p))
             p->visit();
     }
    
    6. 构造后序线索二叉树
    void postThread(ThreadTree &T, ThreadTree &pre)
     {
         if (T)
         {
             postThread(T->lchild, pre);
             postThread(T->rchild, pre);
             T->visit(pre);
         }
     }
     
     void createPostThread(ThreadTree T)
     {
         if (T)
         {
             ThreadNode *pre = NULL;
             postThread(T, pre);
             if(pre->rchild == NULL) //处理最后一个结点
             	pre->rtag = 1;
         }
     }
    
    7. 逆向遍历后序线索二叉树
     ThreadNode *preNode(ThreadNode *p)
     {
         if (p->ltag == 0) //未被线索化
         {
             if (p->rtag == 0)
                 return p->rchild; //有右孩子,前驱为右孩子
         }
         return p->lchild; //被线索化或没被线索化无右孩子,后继都为左孩子
     }
     
     void postOrder(ThreadTree T)
     {
         for (ThreadNode *p = T; p != NULL; p = preNode(p))
             p->visit();
     }
    

树的应用

  • 并查集

    • 数据结构

      树(森林)的双亲表示

      #define Size 100
      int UFSet[Size]
      
    • 相关操作

      1. 初始化

         void init(int s[])
         {
             for (int i = 0; i < size;i++)
                 s[i] = -1;
         }
        
      2. 找某元素的根,用以判断元素是否在一个集合

        最坏:O(n)

        int find(int s[], int x)
        {
            while (s[x] >= 0)
                x = s[x];
            return x;
        }
        
        优化:先找到根结点,再把查找路径上的非根结点挂到根节点上
            
        
      3. 求两个不相交子集合的并集,合并两集合

           void union(int s[],int root1,int root2)
           {
               s[root2] = root1;
           }
           
           优化:小树合并到大树下,用根节点的绝对值表示树的结点总数
               void union(int s[], int root1, int root2)
           {
               if (root1 == root2)
                   return;
               if (s[root2] > s[root1])  //root2为小树
               {
                   s[root1] += s[root2];
                   s[root2] = root1;
               }
               else
               {
                   s[root2] += s[root1];
                   s[root1] = root2;
               }
           }
          ```
        

      在这里插入图片描述

  • 二叉排序树

    中序遍历可得到有序序列

  1. 查找
  • 非递归

    BSTNode *BST_Search(BiTree T,ElemType key)
    {
        while(T!=NULL&&key!=T->data)
        {
            if(key<T->data)
                T = T->lchild;
            else
                T = T->rchild;
        }
        return T;
    }
    
  • 递归

    BSTNode *search(BiTree T, int x)
    {
        if (!T)
            return NULL;
        else
        {
            if (T->key == x)
                return T;
            else if (T->key > x)
                return search(T->lchild, x);
            else if (T->key < x)
                return search(T->rchild, x);
        }
    }
    
  1. 插入

    int insert(BiTree &T, int x)
    {
        if (T == NULL)
        {
            T = new BSTNode;
            T->key = x;
            T->lchild = T->rchild = NULL;
            return 1;
        }
        else if (x == T->key)
            return 0;
        else if (x < T->key)
            return insert(T->lchild, x);
        else
            return insert(T->rchild, x);
    }
    
  2. 构造

    void create(BiTree &T,int x)
    {
        if (insert(T, x) == 0)
            cout << "存在相同的结点,插入失败!" << endl;
    }
    
  3. 删除

    BSTNode *search(BiTree T, int x, BiTree &pre)
    {
        while (T != NULL && x != T->key)
        {
            pre = T;
            if (x < T->key)
                T = T->lchild;
            else
                T = T->rchild;
        }
        return T;
    }
    
    int rMin(BiTree p)
    {
        int m = p->key;
        while (p != NULL)
        {
            if (p->key <= m)
            {
                m = p->key;
                p = p->lchild;
            }
        }
        return m;
    }
    
    void del(BiTree &T, int x)
    {
        BiTree pre = NULL;
        BiTree p = search(T, x, pre);
        if (p == NULL)
            cout << "未查到此值,删除失败!" << endl;
        else
        {
            if (p->lchild == NULL) //无左孩子,直接用右孩子代替
            {
                if (pre->lchild == p) //是前驱结点的左孩子
                    pre->lchild = p->rchild;
                else //是前驱结点的右孩子
                    pre->rchild = p->rchild;
                free(p);
            }
            else if (p->rchild == NULL) //无右孩子,直接用左孩子代替
            {
                if (pre->lchild == p) //是前驱结点的左孩子
                    pre->lchild = p->lchild;
                else //是前驱结点的右孩子
                    pre->rchild = p->lchild;
                free(p);
            }
            else if (p->lchild == NULL&&p->rchild == NULL)  //是叶子结点,直接删除
                free(p);
            else
            {      //左右孩子都有,先找到左子树的最大值或右子树的最小值赋给要删除结点,再利用前两种方法删除这个直接前驱或直接后继
                int m = rMin(p->rchild); 
                del(T, m);
                p->key = m;
            }
        }
    

  • 数据结构

    • 邻接矩阵
    class MGraph{
        char Vex[MaxSize];  //顶点表
        int Edge[MaxSize][MaxSize]; //边表
        int vexNum;    //顶点数
        int arcNum;    //边数
    }
    
    • 邻接表
    class arcNode  //边表结点
    {
        int adjvex;     //该边所指向的顶点的位置
        arcNode *next;  //指向下一个边表结点的指针
        int info;   //边权值
    };
    
    typedef class vNode adjList[Maxsize];
    class vNode   //顶点表结点
    {
        char data;      //顶点信息
        arcNode *first;  //指向第一个与之相连的边表结点
    };
    
    class AlGraph
    {
        adjList vertices; //邻接表
        int vexNum;      //顶点数 
        int arcNum;     //边数
    }; 
    
  • 相关操作

    ​ 以 为例

1. 遍历
  • 广度优先

    void BFSTraverse(Graph G)
    {
        for (int i = 0; i < G.vexNum;i++)
            visited[i] = false;
        initQueue(Q);
        for (int i = 0; i < G.vexNum;i++)
            if(!visited[i])   //对每个连通分量使用一次BFS
                BFS(G, i);
    }
    
    void BFS(Graph G,int v)  //从v出发遍历
    {
        visit(v);   //访问初始顶点
        visited[v] = true;
        enQueue(Q, v);
        while(!isEmpty(Q))
        {
            deQueue(Q, v);
            for (w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G,v,w))
            {
                if(!visited[w])
                {
                    visit(w);
                    visited[w] = true;
                    enQueue(Q, w);
                }
            }
        }
    }
    
  • 深度优先

    void DFSTraverse(Graph G)
    {
        for (int i = 0; i < G.vexNum; i++)
            visited[i] = false;
        initQueue(Q);
        for (int i = 0; i < G.vexNum; i++)
            if (!visited[i]) //对每个连通分量使用一次DFS
                BFS(G, i);
    }
    
    void DFS(Graph G, int v) //从v出发遍历
    {
        visit(v); //访问顶点
        visited[v] = true;
        enQueue(Q, v);
        for (w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G, v, w))
           if(!visited[w])
               DFS(G, w);
    }
    
2. 求x的邻接顶点y的下一个邻接顶点
  • 邻接矩阵

    int nextNeighbor(MGraph G, int x, int y)
    {
        if (x != -1 && y != -1)
        {
            for (int j = y + 1; y < G.vexNum; j++)
            {
                if (G.Edge[x][j] > 0 && G.edge[x][j] < maxWight)
                    									//maxWight为正无穷
                    return j;
            }
        }
        return -1;
    }
    
  • 邻接表

    int nextNeighbor(ALGraph G, int x, int y)
    {
        if (x != -1)
        {
            arcNode *p = G.vertices[x].first;
            while (p != NULL && p->data != y) //寻找邻接顶点y
                p = p->next;
            if (p->next != NULL) //返回下一个邻接顶点
                return p->next->data;
        }
        return -1;
    }
    

图的应用

  • 拓扑排序(邻接表)

    bool TopoLogicalSort(Graph G)
    {
        initStack(S); //暂存入度为0的顶点,栈和队列都可以
        for (int i = 0; i < G.vexNUm; i++)
        {
            if (indegree[i] == 0)
                push(S, i);
        }
        int cnt = 0;
        while (!isEmpty(S))
        {
            pop(S, i);
            visit(i);
            cnt++;
            for (p = G.vertices[i].first; p; p = p->next)
            {
                int v = p->adjvex;
                indegree[v]--;
                if (indegree[v]==0)
                    push(S, v);
            }
        }
        if(cnt<G.vexNum)  // 访问顶点数小于总顶点数,拓扑排序失败,存在回路
            return false;
        else
            return true;
    }
    

排序算法

插入排序

部分有序

  • 直接插入排序

    void inserSort(int a[], int n)
    {
        for (int i = 2; i <= n; i++)
        {
            if (a[i] < a[i - 1])
            {
                a[0] = a[i]; //第一个空出来当哨兵
                int j;
                for (j = i - 1; a[0] < a[j]; j--)   //大的往后挪
                    a[j + 1] = a[j];
                a[j + 1] = a[0];
            }
        }
    }
    
  • 折半插入排序

    void halfInserSort(int a[], int n)
    {
        int low, high, mid;
        for (int i = 2; i <= n; i++)
        {
            a[0] = a[i];   //哨兵
            low = 1;
            high = i - 1;
            while (low <= high) //折半查找插入位置low
            {
                mid = (low + high) / 2;
                if (a[mid] > a[0])
                    high = mid - 1;
                else
                    low = mid + 1;
            }
            for (int j = i - 1; j >= low; j--) // low后面的都有往后挪
                a[j + 1] = a[j];
            a[low] = a[0];
        }
    }
    
  • 希尔排序

    void shellSort(int a[], int n)
    {
        for (int d = n / 2; d >= 1; d /=  2)   //改变步长 
        {
            for (int i = d + 1; i <= n; i++)   //给某一组排序 
            {
                if (a[i] < a[i - d])
                {
                    a[0] = a[i];
                    int j;
                    for (j = i - d; j > 0 && a[0] < a[j]; j -= d)
                        a[j + d] = a[j];   //向后挪查找插入位置
                    a[j + d] = a[0];
                }
            }
        }
    }
    

交换排序

全局有序

  • 冒泡排序

    void bubbleSort(int a[], int n) //从0开始存
    {
        for (int i = 0; i < n - 1; i++) // n个数排序 n-1次
        {
            bool flag = false; //记录是否发生交换
            for (int j = n - 1; j > i; j--)
            {
                if (a[j - 1] > a[j])
                {
                    swap(a[j - 1], a[j]);
                    flag = true;
                }
            }
            if (flag == false) // 一次排序后一次都没交换说明已有序
                return;
        }
    }
    
  • 快速排序

    初始序列越无序越好,划分越均匀越好

    int partition(int a[], int low, int high)
    {
        int p = a[low];    //设区间的第一个元素为枢轴
        while (low < high) //划分确定枢轴最终位置,low=high时
        {
            while (low < high && a[high] >= p)
                high--;
            a[low] = a[high]; //将找到的比枢轴小的元素移动到左边
            while (low < high && a[low] <= p)
                low++;
            a[high] = a[low]; //将找到的比枢轴小的元素移动到左边
        }
        a[low] = p; //确定枢轴最终位置;
        return low;
    }
    
    void quickSort(int a[], int low, int high)
    {
        if (low < high)
        {
            int p = partition(a, low, high);
            quickSort(a, low, p - 1);
            quickSort(a, p + 1, high);
        }
    }
    

选择排序

  • 简单选择排序

    比较次数始终为n(n-1)/2,与数据初始状态无关

    void selectSort(int a[], int n)
    {
        for (int i = 0; i < n - 1; i++)
        {
            int m = i;
            for (int j = i + 1; j < n; j++)
                if (a[j] < a[m])
                    m = j;
            if (m != i)
                swap(a[i], a[m]);
        }
    }
    
  • 堆排序

    数据越多越好

    • 大根堆:升序

      void headAdjust(int a[],int k,int n)  //a[]从1开始存数据
      {
          a[0] = a[k];  //暂存待调整结点值
          for (int i = 2 * k; i <= n;i*=2)  //沿待调整结点一路往下调整
          {
              if (i < n&&a[i]<a[i+1])
                  i++;               //选较大的子结点
              if(a[0]>=a[i])
                  break;   //待调整结点更大,不必调整
              else
              {
                  a[k] = a[i];    //较大子结点的值变成待调整结点位置上的值
                  k = i;    //继续往下调整
              }
          }
          a[k] = a[0];   //找到待调整结点最终位置放入
      }
      
      
      void buildMaxHeap(int a[],int n)
      {
          for (int i = n / 2; i >= 1;i--)  //从最后一个非叶子结点开始逐个调整非叶子结点 
              headAdjust(a, i, n);
      }
      
      void HeapSort(int a[],int n)
      {
          buildMaxHeap(a,n);  //建堆
          for (int i = n; i > 1;i--)  //n-1次交换与调整
          {
              swap(a[i],a[1]);    //堆顶与堆底元素交换,最大元素放最后
              headAdjust(a, 1, i - 1);  //最大元素之前的元素调整
          }
      }
      
    • 小根堆:降序

      void headAdjust(int a[], int k, int n) // a[]从1开始存数据
      {
          a[0] = a[k];                        //暂存待调整结点值
          for (int i = 2 * k; i <= n; i *= 2) //沿待调整结点一路往下调整
          {
              if (i < n && a[i] > a[i + 1])
                  i++; //选较小的子结点
              if (a[0] <= a[i])
                  break; //待调整结点更小,不必调整
              else
              {
                  a[k] = a[i]; //较小子结点的值变成待调整结点位置上的值
                  k = i;       //继续往下调整
              }
          }
          a[k] = a[0]; //找到待调整结点最终位置放入
      }
      
      void buildMinHeap(int a[], int n)
      {
          for (int i = n / 2; i >= 1; i--) //从最后一个非叶子结点开始逐个调整非叶子结点
              headAdjust(a, i, n);
      }
      
      void HeapSort(int a[], int n)
      {
          buildMinHeap(a, n);         //建堆
          for (int i = n; i > 1; i--) // n-1次交换与调整
          {
              swap(a[i], a[1]);        //堆顶与堆底元素交换,最大元素放最后
              headAdjust(a, 1, i - 1);   //调整最大元素之前的所有元素
          }
      }
      

归并排序

int *b=new int[n] ;
void merge(int a[],int low,int mid,int high)
{
    int i,j,k;
    for (k = low; k <= high; k++)
        b[k] = a[k];
    for (i = low, j = mid + 1, k = i; i <=mid && j <= high;k++)
    {
        if(b[i]<=b[j])
            a[k] = b[i++];
        else
            a[k] = b[j++];
    }
    while(i<=mid)
        a[k++] = b[i++];
    while(j<=high)
        a[k++] = b[j++];
}

void mergeSort(int a[],int low,int high)
{
    if(low<high)
    {
        int mid = (low + high) / 2;
        mergeSort(a,low,mid);
        mergeSort(a, mid+1, high);
        merge(a, low, mid, high);
    }
}

基数排序

依据关键字排序,越关键越后排

🔅排序比较

在这里插入图片描述

最后给大家推荐一个包含数据结构里面所有算法的动态演示网站:
可以更生动的理解算法细节,click me!

阅读到这里要给你一个大大的赞,全部掌握的你太棒啦!继续在计算机学习领域加油吧!整理不易,别忘了点赞收藏评论哦~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值